File scoped namespaces
This commit is contained in:
@@ -4,70 +4,69 @@ using Windows.UI.Xaml;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.UWP.Controls;
|
||||
|
||||
namespace Wino.Controls
|
||||
namespace Wino.Controls;
|
||||
|
||||
public partial class AccountNavigationItem : WinoNavigationViewItem
|
||||
{
|
||||
public partial class AccountNavigationItem : WinoNavigationViewItem
|
||||
|
||||
public static readonly DependencyProperty IsActiveAccountProperty = DependencyProperty.Register(nameof(IsActiveAccount), typeof(bool), typeof(AccountNavigationItem), new PropertyMetadata(false, new PropertyChangedCallback(OnIsActiveAccountChanged)));
|
||||
public static readonly DependencyProperty BindingDataProperty = DependencyProperty.Register(nameof(BindingData), typeof(IAccountMenuItem), typeof(AccountNavigationItem), new PropertyMetadata(null));
|
||||
|
||||
|
||||
public bool IsActiveAccount
|
||||
{
|
||||
get { return (bool)GetValue(IsActiveAccountProperty); }
|
||||
set { SetValue(IsActiveAccountProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsActiveAccountProperty = DependencyProperty.Register(nameof(IsActiveAccount), typeof(bool), typeof(AccountNavigationItem), new PropertyMetadata(false, new PropertyChangedCallback(OnIsActiveAccountChanged)));
|
||||
public static readonly DependencyProperty BindingDataProperty = DependencyProperty.Register(nameof(BindingData), typeof(IAccountMenuItem), typeof(AccountNavigationItem), new PropertyMetadata(null));
|
||||
public IAccountMenuItem BindingData
|
||||
{
|
||||
get { return (IAccountMenuItem)GetValue(BindingDataProperty); }
|
||||
set { SetValue(BindingDataProperty, value); }
|
||||
}
|
||||
|
||||
private const string PART_NavigationViewItemMenuItemsHost = "NavigationViewItemMenuItemsHost";
|
||||
private const string PART_SelectionIndicator = "CustomSelectionIndicator";
|
||||
|
||||
public bool IsActiveAccount
|
||||
{
|
||||
get { return (bool)GetValue(IsActiveAccountProperty); }
|
||||
set { SetValue(IsActiveAccountProperty, value); }
|
||||
}
|
||||
private ItemsRepeater _itemsRepeater;
|
||||
private Windows.UI.Xaml.Shapes.Rectangle _selectionIndicator;
|
||||
|
||||
public IAccountMenuItem BindingData
|
||||
{
|
||||
get { return (IAccountMenuItem)GetValue(BindingDataProperty); }
|
||||
set { SetValue(BindingDataProperty, value); }
|
||||
}
|
||||
public AccountNavigationItem()
|
||||
{
|
||||
DefaultStyleKey = typeof(AccountNavigationItem);
|
||||
}
|
||||
|
||||
private const string PART_NavigationViewItemMenuItemsHost = "NavigationViewItemMenuItemsHost";
|
||||
private const string PART_SelectionIndicator = "CustomSelectionIndicator";
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
private ItemsRepeater _itemsRepeater;
|
||||
private Windows.UI.Xaml.Shapes.Rectangle _selectionIndicator;
|
||||
_itemsRepeater = GetTemplateChild(PART_NavigationViewItemMenuItemsHost) as ItemsRepeater;
|
||||
_selectionIndicator = GetTemplateChild(PART_SelectionIndicator) as Windows.UI.Xaml.Shapes.Rectangle;
|
||||
|
||||
public AccountNavigationItem()
|
||||
{
|
||||
DefaultStyleKey = typeof(AccountNavigationItem);
|
||||
}
|
||||
if (_itemsRepeater == null) return;
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
(_itemsRepeater.Layout as StackLayout).Spacing = 0;
|
||||
|
||||
_itemsRepeater = GetTemplateChild(PART_NavigationViewItemMenuItemsHost) as ItemsRepeater;
|
||||
_selectionIndicator = GetTemplateChild(PART_SelectionIndicator) as Windows.UI.Xaml.Shapes.Rectangle;
|
||||
UpdateSelectionBorder();
|
||||
}
|
||||
|
||||
if (_itemsRepeater == null) return;
|
||||
private static void OnIsActiveAccountChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (obj is AccountNavigationItem control)
|
||||
control.UpdateSelectionBorder();
|
||||
}
|
||||
|
||||
(_itemsRepeater.Layout as StackLayout).Spacing = 0;
|
||||
private void UpdateSelectionBorder()
|
||||
{
|
||||
if (_selectionIndicator == null) return;
|
||||
|
||||
UpdateSelectionBorder();
|
||||
}
|
||||
// Adjsuting Margin in the styles are not possible due to the fact that we use the same tempalte for different types of menu items.
|
||||
// Account templates listed under merged accounts will have Padding of 44. We must adopt to that.
|
||||
|
||||
private static void OnIsActiveAccountChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (obj is AccountNavigationItem control)
|
||||
control.UpdateSelectionBorder();
|
||||
}
|
||||
bool hasParentMenuItem = BindingData is IAccountMenuItem accountMenuItem && accountMenuItem.ParentMenuItem != null;
|
||||
|
||||
private void UpdateSelectionBorder()
|
||||
{
|
||||
if (_selectionIndicator == null) return;
|
||||
|
||||
// Adjsuting Margin in the styles are not possible due to the fact that we use the same tempalte for different types of menu items.
|
||||
// Account templates listed under merged accounts will have Padding of 44. We must adopt to that.
|
||||
|
||||
bool hasParentMenuItem = BindingData is IAccountMenuItem accountMenuItem && accountMenuItem.ParentMenuItem != null;
|
||||
|
||||
_selectionIndicator.Margin = !hasParentMenuItem ? new Thickness(-44, 12, 0, 12) : new Thickness(-60, 12, -60, 12);
|
||||
_selectionIndicator.Scale = IsActiveAccount ? new Vector3(1, 1, 1) : new Vector3(0, 0, 0);
|
||||
_selectionIndicator.Visibility = IsActiveAccount ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
_selectionIndicator.Margin = !hasParentMenuItem ? new Thickness(-44, 12, 0, 12) : new Thickness(-60, 12, -60, 12);
|
||||
_selectionIndicator.Scale = IsActiveAccount ? new Vector3(1, 1, 1) : new Vector3(0, 0, 0);
|
||||
_selectionIndicator.Visibility = IsActiveAccount ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,254 +13,244 @@ using Wino.Extensions;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.Mail.ViewModels.Messages;
|
||||
|
||||
namespace Wino.Controls.Advanced
|
||||
namespace Wino.Controls.Advanced;
|
||||
|
||||
/// <summary>
|
||||
/// Custom ListView control that handles multiple selection with Extended/Multiple selection mode
|
||||
/// and supports threads.
|
||||
/// </summary>
|
||||
public partial class WinoListView : ListView, IDisposable
|
||||
{
|
||||
private ILogger logger = Log.ForContext<WinoListView>();
|
||||
|
||||
private const string PART_ScrollViewer = "ScrollViewer";
|
||||
private ScrollViewer internalScrollviewer;
|
||||
|
||||
/// <summary>
|
||||
/// Custom ListView control that handles multiple selection with Extended/Multiple selection mode
|
||||
/// and supports threads.
|
||||
/// Gets or sets whether this ListView belongs to thread items.
|
||||
/// This is important for detecting selected items etc.
|
||||
/// </summary>
|
||||
public partial class WinoListView : ListView, IDisposable
|
||||
public bool IsThreadListView
|
||||
{
|
||||
private ILogger logger = Log.ForContext<WinoListView>();
|
||||
get { return (bool)GetValue(IsThreadListViewProperty); }
|
||||
set { SetValue(IsThreadListViewProperty, value); }
|
||||
}
|
||||
|
||||
private const string PART_ScrollViewer = "ScrollViewer";
|
||||
private ScrollViewer internalScrollviewer;
|
||||
public ICommand ItemDeletedCommand
|
||||
{
|
||||
get { return (ICommand)GetValue(ItemDeletedCommandProperty); }
|
||||
set { SetValue(ItemDeletedCommandProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether this ListView belongs to thread items.
|
||||
/// This is important for detecting selected items etc.
|
||||
/// </summary>
|
||||
public bool IsThreadListView
|
||||
public ICommand LoadMoreCommand
|
||||
{
|
||||
get { return (ICommand)GetValue(LoadMoreCommandProperty); }
|
||||
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));
|
||||
|
||||
public WinoListView()
|
||||
{
|
||||
CanDragItems = true;
|
||||
IsItemClickEnabled = true;
|
||||
IsMultiSelectCheckBoxEnabled = true;
|
||||
IsRightTapEnabled = true;
|
||||
SelectionMode = ListViewSelectionMode.Extended;
|
||||
ShowsScrollingPlaceholders = false;
|
||||
SingleSelectionFollowsFocus = true;
|
||||
|
||||
DragItemsCompleted += ItemDragCompleted;
|
||||
DragItemsStarting += ItemDragStarting;
|
||||
SelectionChanged += SelectedItemsChanged;
|
||||
ProcessKeyboardAccelerators += ProcessDelKey;
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
internalScrollviewer = GetTemplateChild(PART_ScrollViewer) as ScrollViewer;
|
||||
|
||||
if (internalScrollviewer == null)
|
||||
{
|
||||
get { return (bool)GetValue(IsThreadListViewProperty); }
|
||||
set { SetValue(IsThreadListViewProperty, value); }
|
||||
logger.Warning("WinoListView does not have an internal ScrollViewer. Infinite scrolling behavior might be effected.");
|
||||
return;
|
||||
}
|
||||
|
||||
public ICommand ItemDeletedCommand
|
||||
internalScrollviewer.ViewChanged -= InternalScrollVeiwerViewChanged;
|
||||
internalScrollviewer.ViewChanged += InternalScrollVeiwerViewChanged;
|
||||
}
|
||||
|
||||
private static void OnIsThreadViewChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (obj is WinoListView winoListView)
|
||||
{
|
||||
get { return (ICommand)GetValue(ItemDeletedCommandProperty); }
|
||||
set { SetValue(ItemDeletedCommandProperty, value); }
|
||||
winoListView.AdjustThreadViewContainerVisuals();
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand LoadMoreCommand
|
||||
private void AdjustThreadViewContainerVisuals()
|
||||
{
|
||||
if (IsThreadListView)
|
||||
{
|
||||
get { return (ICommand)GetValue(LoadMoreCommandProperty); }
|
||||
set { SetValue(LoadMoreCommandProperty, value); }
|
||||
ItemContainerTransitions.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsThreadScrollingEnabled
|
||||
private double lastestRaisedOffset = 0;
|
||||
private int lastItemSize = 0;
|
||||
|
||||
// TODO: This is buggy. Does not work all the time. Debug.
|
||||
|
||||
private void InternalScrollVeiwerViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
|
||||
{
|
||||
if (internalScrollviewer == null) return;
|
||||
|
||||
// No need to raise init request if there are no items in the list.
|
||||
if (Items.Count == 0) return;
|
||||
|
||||
// If the scrolling is finished, check the current viewport height.
|
||||
if (e.IsIntermediate)
|
||||
{
|
||||
get { return (bool)GetValue(IsThreadScrollingEnabledProperty); }
|
||||
set { SetValue(IsThreadScrollingEnabledProperty, value); }
|
||||
}
|
||||
var currentOffset = internalScrollviewer.VerticalOffset;
|
||||
var maxOffset = internalScrollviewer.ScrollableHeight;
|
||||
|
||||
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));
|
||||
|
||||
public WinoListView()
|
||||
{
|
||||
CanDragItems = true;
|
||||
IsItemClickEnabled = true;
|
||||
IsMultiSelectCheckBoxEnabled = true;
|
||||
IsRightTapEnabled = true;
|
||||
SelectionMode = ListViewSelectionMode.Extended;
|
||||
ShowsScrollingPlaceholders = false;
|
||||
SingleSelectionFollowsFocus = true;
|
||||
|
||||
DragItemsCompleted += ItemDragCompleted;
|
||||
DragItemsStarting += ItemDragStarting;
|
||||
SelectionChanged += SelectedItemsChanged;
|
||||
ProcessKeyboardAccelerators += ProcessDelKey;
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
internalScrollviewer = GetTemplateChild(PART_ScrollViewer) as ScrollViewer;
|
||||
|
||||
if (internalScrollviewer == null)
|
||||
if (currentOffset + 10 >= maxOffset && lastestRaisedOffset != maxOffset && Items.Count != lastItemSize)
|
||||
{
|
||||
logger.Warning("WinoListView does not have an internal ScrollViewer. Infinite scrolling behavior might be effected.");
|
||||
return;
|
||||
}
|
||||
// We must load more.
|
||||
lastestRaisedOffset = maxOffset;
|
||||
lastItemSize = Items.Count;
|
||||
|
||||
internalScrollviewer.ViewChanged -= InternalScrollVeiwerViewChanged;
|
||||
internalScrollviewer.ViewChanged += InternalScrollVeiwerViewChanged;
|
||||
}
|
||||
|
||||
private static void OnIsThreadViewChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (obj is WinoListView winoListView)
|
||||
{
|
||||
winoListView.AdjustThreadViewContainerVisuals();
|
||||
LoadMoreCommand?.Execute(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AdjustThreadViewContainerVisuals()
|
||||
private void ProcessDelKey(UIElement sender, Windows.UI.Xaml.Input.ProcessKeyboardAcceleratorEventArgs args)
|
||||
{
|
||||
if (args.Key == Windows.System.VirtualKey.Delete)
|
||||
{
|
||||
if (IsThreadListView)
|
||||
{
|
||||
ItemContainerTransitions.Clear();
|
||||
}
|
||||
args.Handled = true;
|
||||
|
||||
ItemDeletedCommand?.Execute(MailOperation.SoftDelete);
|
||||
}
|
||||
}
|
||||
|
||||
private double lastestRaisedOffset = 0;
|
||||
private int lastItemSize = 0;
|
||||
|
||||
// TODO: This is buggy. Does not work all the time. Debug.
|
||||
|
||||
private void InternalScrollVeiwerViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
|
||||
private void ItemDragCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
|
||||
{
|
||||
if (args.Items.Any(a => a is MailItemViewModel))
|
||||
{
|
||||
if (internalScrollviewer == null) return;
|
||||
|
||||
// No need to raise init request if there are no items in the list.
|
||||
if (Items.Count == 0) return;
|
||||
|
||||
// If the scrolling is finished, check the current viewport height.
|
||||
if (e.IsIntermediate)
|
||||
{
|
||||
var currentOffset = internalScrollviewer.VerticalOffset;
|
||||
var maxOffset = internalScrollviewer.ScrollableHeight;
|
||||
|
||||
if (currentOffset + 10 >= maxOffset && lastestRaisedOffset != maxOffset && Items.Count != lastItemSize)
|
||||
{
|
||||
// We must load more.
|
||||
lastestRaisedOffset = maxOffset;
|
||||
lastItemSize = Items.Count;
|
||||
|
||||
LoadMoreCommand?.Execute(null);
|
||||
}
|
||||
}
|
||||
args.Items.Cast<MailItemViewModel>().ForEach(a => a.IsCustomFocused = false);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessDelKey(UIElement sender, Windows.UI.Xaml.Input.ProcessKeyboardAcceleratorEventArgs args)
|
||||
private void ItemDragStarting(object sender, DragItemsStartingEventArgs args)
|
||||
{
|
||||
// Dragging multiple mails from different accounts/folders are supported with the condition below:
|
||||
// All mails belongs to the drag will be matched on the dropped folder's account.
|
||||
// Meaning that if users drag 1 mail from Account A/Inbox and 1 mail from Account B/Inbox,
|
||||
// and drop to Account A/Inbox, the mail from Account B/Inbox will NOT be moved.
|
||||
|
||||
if (IsThreadListView)
|
||||
{
|
||||
if (args.Key == Windows.System.VirtualKey.Delete)
|
||||
{
|
||||
args.Handled = true;
|
||||
var allItems = args.Items.Cast<MailItemViewModel>();
|
||||
|
||||
ItemDeletedCommand?.Execute(MailOperation.SoftDelete);
|
||||
}
|
||||
// Highlight all items
|
||||
allItems.ForEach(a => a.IsCustomFocused = true);
|
||||
|
||||
// Set native drag arg properties.
|
||||
|
||||
var dragPackage = new MailDragPackage(allItems.Cast<IMailItem>());
|
||||
|
||||
args.Data.Properties.Add(nameof(MailDragPackage), dragPackage);
|
||||
}
|
||||
|
||||
private void ItemDragCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
|
||||
else
|
||||
{
|
||||
if (args.Items.Any(a => a is MailItemViewModel))
|
||||
{
|
||||
args.Items.Cast<MailItemViewModel>().ForEach(a => a.IsCustomFocused = false);
|
||||
}
|
||||
var dragPackage = new MailDragPackage(args.Items.Cast<IMailItem>());
|
||||
|
||||
args.Data.Properties.Add(nameof(MailDragPackage), dragPackage);
|
||||
}
|
||||
}
|
||||
|
||||
private void ItemDragStarting(object sender, DragItemsStartingEventArgs args)
|
||||
public void ChangeSelectionMode(ListViewSelectionMode selectionMode)
|
||||
{
|
||||
SelectionMode = selectionMode;
|
||||
|
||||
if (!IsThreadListView)
|
||||
{
|
||||
// Dragging multiple mails from different accounts/folders are supported with the condition below:
|
||||
// All mails belongs to the drag will be matched on the dropped folder's account.
|
||||
// Meaning that if users drag 1 mail from Account A/Inbox and 1 mail from Account B/Inbox,
|
||||
// and drop to Account A/Inbox, the mail from Account B/Inbox will NOT be moved.
|
||||
|
||||
if (IsThreadListView)
|
||||
{
|
||||
var allItems = args.Items.Cast<MailItemViewModel>();
|
||||
|
||||
// Highlight all items
|
||||
allItems.ForEach(a => a.IsCustomFocused = true);
|
||||
|
||||
// Set native drag arg properties.
|
||||
|
||||
var dragPackage = new MailDragPackage(allItems.Cast<IMailItem>());
|
||||
|
||||
args.Data.Properties.Add(nameof(MailDragPackage), dragPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
var dragPackage = new MailDragPackage(args.Items.Cast<IMailItem>());
|
||||
|
||||
args.Data.Properties.Add(nameof(MailDragPackage), dragPackage);
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeSelectionMode(ListViewSelectionMode selectionMode)
|
||||
{
|
||||
SelectionMode = selectionMode;
|
||||
|
||||
if (!IsThreadListView)
|
||||
{
|
||||
Items.Where(a => a is ThreadMailItemViewModel).Cast<ThreadMailItemViewModel>().ForEach(c =>
|
||||
{
|
||||
var threadListView = GetThreadInternalListView(c);
|
||||
|
||||
if (threadListView != null)
|
||||
{
|
||||
threadListView.SelectionMode = selectionMode;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the container for given mail item and adds it to selected items.
|
||||
/// </summary>
|
||||
/// <param name="mailItemViewModel">Mail to be added to selected items.</param>
|
||||
/// <returns>Whether selection was successful or not.</returns>
|
||||
public bool SelectMailItemContainer(MailItemViewModel mailItemViewModel)
|
||||
{
|
||||
var itemContainer = ContainerFromItem(mailItemViewModel);
|
||||
|
||||
// This item might be in thread container.
|
||||
if (itemContainer == null)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
Items.OfType<ThreadMailItemViewModel>().ForEach(c =>
|
||||
{
|
||||
if (!found)
|
||||
{
|
||||
var threadListView = GetThreadInternalListView(c);
|
||||
|
||||
if (threadListView != null)
|
||||
found = threadListView.SelectMailItemContainer(mailItemViewModel);
|
||||
}
|
||||
});
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
SelectedItems.Add(mailItemViewModel);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recursively clears all selections except the given mail.
|
||||
/// </summary>
|
||||
/// <param name="exceptViewModel">Exceptional mail item to be not unselected.</param>
|
||||
/// <param name="preserveThreadExpanding">Whether expansion states of thread containers should stay as it is or not.</param>
|
||||
public void ClearSelections(MailItemViewModel exceptViewModel = null, bool preserveThreadExpanding = false)
|
||||
{
|
||||
SelectedItems.Clear();
|
||||
|
||||
Items.Where(a => a is ThreadMailItemViewModel).Cast<ThreadMailItemViewModel>().ForEach(c =>
|
||||
{
|
||||
var threadListView = GetThreadInternalListView(c);
|
||||
|
||||
if (threadListView == null)
|
||||
return;
|
||||
|
||||
if (exceptViewModel != null)
|
||||
if (threadListView != null)
|
||||
{
|
||||
if (!threadListView.SelectedItems.Contains(exceptViewModel))
|
||||
{
|
||||
if (!preserveThreadExpanding)
|
||||
{
|
||||
c.IsThreadExpanded = false;
|
||||
}
|
||||
|
||||
threadListView.SelectedItems.Clear();
|
||||
}
|
||||
threadListView.SelectionMode = selectionMode;
|
||||
}
|
||||
else
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the container for given mail item and adds it to selected items.
|
||||
/// </summary>
|
||||
/// <param name="mailItemViewModel">Mail to be added to selected items.</param>
|
||||
/// <returns>Whether selection was successful or not.</returns>
|
||||
public bool SelectMailItemContainer(MailItemViewModel mailItemViewModel)
|
||||
{
|
||||
var itemContainer = ContainerFromItem(mailItemViewModel);
|
||||
|
||||
// This item might be in thread container.
|
||||
if (itemContainer == null)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
Items.OfType<ThreadMailItemViewModel>().ForEach(c =>
|
||||
{
|
||||
if (!found)
|
||||
{
|
||||
var threadListView = GetThreadInternalListView(c);
|
||||
|
||||
if (threadListView != null)
|
||||
found = threadListView.SelectMailItemContainer(mailItemViewModel);
|
||||
}
|
||||
});
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
SelectedItems.Add(mailItemViewModel);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recursively clears all selections except the given mail.
|
||||
/// </summary>
|
||||
/// <param name="exceptViewModel">Exceptional mail item to be not unselected.</param>
|
||||
/// <param name="preserveThreadExpanding">Whether expansion states of thread containers should stay as it is or not.</param>
|
||||
public void ClearSelections(MailItemViewModel exceptViewModel = null, bool preserveThreadExpanding = false)
|
||||
{
|
||||
SelectedItems.Clear();
|
||||
|
||||
Items.Where(a => a is ThreadMailItemViewModel).Cast<ThreadMailItemViewModel>().ForEach(c =>
|
||||
{
|
||||
var threadListView = GetThreadInternalListView(c);
|
||||
|
||||
if (threadListView == null)
|
||||
return;
|
||||
|
||||
if (exceptViewModel != null)
|
||||
{
|
||||
if (!threadListView.SelectedItems.Contains(exceptViewModel))
|
||||
{
|
||||
if (!preserveThreadExpanding)
|
||||
{
|
||||
@@ -269,150 +259,159 @@ namespace Wino.Controls.Advanced
|
||||
|
||||
threadListView.SelectedItems.Clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recursively selects all mails, including thread items.
|
||||
/// </summary>
|
||||
public void SelectAllWino()
|
||||
{
|
||||
SelectAll();
|
||||
|
||||
Items.Where(a => a is ThreadMailItemViewModel).Cast<ThreadMailItemViewModel>().ForEach(c =>
|
||||
}
|
||||
else
|
||||
{
|
||||
c.IsThreadExpanded = true;
|
||||
|
||||
var threadListView = GetThreadInternalListView(c);
|
||||
|
||||
threadListView?.SelectAll();
|
||||
});
|
||||
}
|
||||
|
||||
// SelectedItems changed.
|
||||
private void SelectedItemsChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (e.RemovedItems != null)
|
||||
{
|
||||
foreach (var removedItem in e.RemovedItems)
|
||||
if (!preserveThreadExpanding)
|
||||
{
|
||||
if (removedItem is MailItemViewModel removedMailItemViewModel)
|
||||
{
|
||||
// Mail item un-selected.
|
||||
c.IsThreadExpanded = false;
|
||||
}
|
||||
|
||||
removedMailItemViewModel.IsSelected = false;
|
||||
WeakReferenceMessenger.Default.Send(new MailItemSelectionRemovedEvent(removedMailItemViewModel));
|
||||
}
|
||||
else if (removedItem is ThreadMailItemViewModel removedThreadItemViewModel)
|
||||
{
|
||||
removedThreadItemViewModel.IsThreadExpanded = false;
|
||||
}
|
||||
threadListView.SelectedItems.Clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recursively selects all mails, including thread items.
|
||||
/// </summary>
|
||||
public void SelectAllWino()
|
||||
{
|
||||
SelectAll();
|
||||
|
||||
Items.Where(a => a is ThreadMailItemViewModel).Cast<ThreadMailItemViewModel>().ForEach(c =>
|
||||
{
|
||||
c.IsThreadExpanded = true;
|
||||
|
||||
var threadListView = GetThreadInternalListView(c);
|
||||
|
||||
threadListView?.SelectAll();
|
||||
});
|
||||
}
|
||||
|
||||
// SelectedItems changed.
|
||||
private void SelectedItemsChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (e.RemovedItems != null)
|
||||
{
|
||||
foreach (var removedItem in e.RemovedItems)
|
||||
{
|
||||
if (removedItem is MailItemViewModel removedMailItemViewModel)
|
||||
{
|
||||
// Mail item un-selected.
|
||||
|
||||
removedMailItemViewModel.IsSelected = false;
|
||||
WeakReferenceMessenger.Default.Send(new MailItemSelectionRemovedEvent(removedMailItemViewModel));
|
||||
}
|
||||
else if (removedItem is ThreadMailItemViewModel removedThreadItemViewModel)
|
||||
{
|
||||
removedThreadItemViewModel.IsThreadExpanded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (e.AddedItems != null)
|
||||
if (e.AddedItems != null)
|
||||
{
|
||||
foreach (var addedItem in e.AddedItems)
|
||||
{
|
||||
foreach (var addedItem in e.AddedItems)
|
||||
if (addedItem is MailItemViewModel addedMailItemViewModel)
|
||||
{
|
||||
if (addedItem is MailItemViewModel addedMailItemViewModel)
|
||||
// Mail item selected.
|
||||
|
||||
addedMailItemViewModel.IsSelected = true;
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new MailItemSelectedEvent(addedMailItemViewModel));
|
||||
}
|
||||
else if (addedItem is ThreadMailItemViewModel threadMailItemViewModel)
|
||||
{
|
||||
if (IsThreadScrollingEnabled)
|
||||
{
|
||||
// Mail item selected.
|
||||
|
||||
addedMailItemViewModel.IsSelected = true;
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new MailItemSelectedEvent(addedMailItemViewModel));
|
||||
}
|
||||
else if (addedItem is ThreadMailItemViewModel threadMailItemViewModel)
|
||||
{
|
||||
if (IsThreadScrollingEnabled)
|
||||
if (internalScrollviewer != null && ContainerFromItem(threadMailItemViewModel) is FrameworkElement threadFrameworkElement)
|
||||
{
|
||||
if (internalScrollviewer != null && ContainerFromItem(threadMailItemViewModel) is FrameworkElement threadFrameworkElement)
|
||||
{
|
||||
internalScrollviewer.ScrollToElement(threadFrameworkElement, true, true, bringToTopOrLeft: true);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to select first item.
|
||||
if (GetThreadInternalListView(threadMailItemViewModel) is WinoListView internalListView)
|
||||
{
|
||||
internalListView.SelectFirstItem();
|
||||
internalScrollviewer.ScrollToElement(threadFrameworkElement, true, true, bringToTopOrLeft: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsThreadListView)
|
||||
{
|
||||
if (SelectionMode == ListViewSelectionMode.Extended && SelectedItems.Count == 1)
|
||||
{
|
||||
// Only 1 single item is selected in extended mode for main list view.
|
||||
// We should un-select all thread items.
|
||||
|
||||
Items.Where(a => a is ThreadMailItemViewModel).Cast<ThreadMailItemViewModel>().ForEach(c =>
|
||||
// Try to select first item.
|
||||
if (GetThreadInternalListView(threadMailItemViewModel) is WinoListView internalListView)
|
||||
{
|
||||
// c.IsThreadExpanded = false;
|
||||
|
||||
var threadListView = GetThreadInternalListView(c);
|
||||
|
||||
threadListView?.SelectedItems.Clear();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
internalListView.SelectFirstItem();
|
||||
}
|
||||
|
||||
firstMailItemViewModel.IsSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private WinoListView GetThreadInternalListView(ThreadMailItemViewModel threadMailItemViewModel)
|
||||
if (!IsThreadListView)
|
||||
{
|
||||
var itemContainer = ContainerFromItem(threadMailItemViewModel);
|
||||
|
||||
if (itemContainer is ListViewItem listItem)
|
||||
if (SelectionMode == ListViewSelectionMode.Extended && SelectedItems.Count == 1)
|
||||
{
|
||||
var expander = listItem.GetChildByName<WinoExpander>("ThreadExpander");
|
||||
// Only 1 single item is selected in extended mode for main list view.
|
||||
// We should un-select all thread items.
|
||||
|
||||
if (expander != null)
|
||||
return expander.Content as WinoListView;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DragItemsCompleted -= ItemDragCompleted;
|
||||
DragItemsStarting -= ItemDragStarting;
|
||||
SelectionChanged -= SelectedItemsChanged;
|
||||
ProcessKeyboardAccelerators -= ProcessDelKey;
|
||||
|
||||
if (internalScrollviewer != null)
|
||||
{
|
||||
internalScrollviewer.ViewChanged -= InternalScrollVeiwerViewChanged;
|
||||
}
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
if (item is ThreadMailItemViewModel threadMailItemViewModel)
|
||||
Items.Where(a => a is ThreadMailItemViewModel).Cast<ThreadMailItemViewModel>().ForEach(c =>
|
||||
{
|
||||
var threadListView = GetThreadInternalListView(threadMailItemViewModel);
|
||||
threadListView?.Dispose();
|
||||
// c.IsThreadExpanded = false;
|
||||
|
||||
var threadListView = GetThreadInternalListView(c);
|
||||
|
||||
threadListView?.SelectedItems.Clear();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private WinoListView GetThreadInternalListView(ThreadMailItemViewModel threadMailItemViewModel)
|
||||
{
|
||||
var itemContainer = ContainerFromItem(threadMailItemViewModel);
|
||||
|
||||
if (itemContainer is ListViewItem listItem)
|
||||
{
|
||||
var expander = listItem.GetChildByName<WinoExpander>("ThreadExpander");
|
||||
|
||||
if (expander != null)
|
||||
return expander.Content as WinoListView;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DragItemsCompleted -= ItemDragCompleted;
|
||||
DragItemsStarting -= ItemDragStarting;
|
||||
SelectionChanged -= SelectedItemsChanged;
|
||||
ProcessKeyboardAccelerators -= ProcessDelKey;
|
||||
|
||||
if (internalScrollviewer != null)
|
||||
{
|
||||
internalScrollviewer.ViewChanged -= InternalScrollVeiwerViewChanged;
|
||||
}
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
if (item is ThreadMailItemViewModel threadMailItemViewModel)
|
||||
{
|
||||
var threadListView = GetThreadInternalListView(threadMailItemViewModel);
|
||||
threadListView?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,186 +13,185 @@ using Windows.UI.Xaml.Media.Imaging;
|
||||
using Windows.UI.Xaml.Shapes;
|
||||
using Wino.Core.UWP.Services;
|
||||
|
||||
namespace Wino.Controls
|
||||
namespace Wino.Controls;
|
||||
|
||||
public partial class ImagePreviewControl : Control
|
||||
{
|
||||
public partial class ImagePreviewControl : Control
|
||||
private const string PART_EllipseInitialsGrid = "EllipseInitialsGrid";
|
||||
private const string PART_InitialsTextBlock = "InitialsTextBlock";
|
||||
private const string PART_KnownHostImage = "KnownHostImage";
|
||||
private const string PART_Ellipse = "Ellipse";
|
||||
|
||||
#region Dependency Properties
|
||||
|
||||
public static readonly DependencyProperty FromNameProperty = DependencyProperty.Register(nameof(FromName), typeof(string), typeof(ImagePreviewControl), new PropertyMetadata(string.Empty, OnAddressInformationChanged));
|
||||
public static readonly DependencyProperty FromAddressProperty = DependencyProperty.Register(nameof(FromAddress), typeof(string), typeof(ImagePreviewControl), new PropertyMetadata(string.Empty, OnAddressInformationChanged));
|
||||
public static readonly DependencyProperty SenderContactPictureProperty = DependencyProperty.Register(nameof(SenderContactPicture), typeof(string), typeof(ImagePreviewControl), new PropertyMetadata(string.Empty, new PropertyChangedCallback(OnAddressInformationChanged)));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets base64 string of the sender contact picture.
|
||||
/// </summary>
|
||||
public string SenderContactPicture
|
||||
{
|
||||
private const string PART_EllipseInitialsGrid = "EllipseInitialsGrid";
|
||||
private const string PART_InitialsTextBlock = "InitialsTextBlock";
|
||||
private const string PART_KnownHostImage = "KnownHostImage";
|
||||
private const string PART_Ellipse = "Ellipse";
|
||||
get { return (string)GetValue(SenderContactPictureProperty); }
|
||||
set { SetValue(SenderContactPictureProperty, value); }
|
||||
}
|
||||
|
||||
#region Dependency Properties
|
||||
public string FromName
|
||||
{
|
||||
get { return (string)GetValue(FromNameProperty); }
|
||||
set { SetValue(FromNameProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FromNameProperty = DependencyProperty.Register(nameof(FromName), typeof(string), typeof(ImagePreviewControl), new PropertyMetadata(string.Empty, OnAddressInformationChanged));
|
||||
public static readonly DependencyProperty FromAddressProperty = DependencyProperty.Register(nameof(FromAddress), typeof(string), typeof(ImagePreviewControl), new PropertyMetadata(string.Empty, OnAddressInformationChanged));
|
||||
public static readonly DependencyProperty SenderContactPictureProperty = DependencyProperty.Register(nameof(SenderContactPicture), typeof(string), typeof(ImagePreviewControl), new PropertyMetadata(string.Empty, new PropertyChangedCallback(OnAddressInformationChanged)));
|
||||
public string FromAddress
|
||||
{
|
||||
get { return (string)GetValue(FromAddressProperty); }
|
||||
set { SetValue(FromAddressProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets base64 string of the sender contact picture.
|
||||
/// </summary>
|
||||
public string SenderContactPicture
|
||||
#endregion
|
||||
|
||||
private Ellipse Ellipse;
|
||||
private Grid InitialsGrid;
|
||||
private TextBlock InitialsTextblock;
|
||||
private Image KnownHostImage;
|
||||
private CancellationTokenSource contactPictureLoadingCancellationTokenSource;
|
||||
|
||||
public ImagePreviewControl()
|
||||
{
|
||||
DefaultStyleKey = nameof(ImagePreviewControl);
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
InitialsGrid = GetTemplateChild(PART_EllipseInitialsGrid) as Grid;
|
||||
InitialsTextblock = GetTemplateChild(PART_InitialsTextBlock) as TextBlock;
|
||||
KnownHostImage = GetTemplateChild(PART_KnownHostImage) as Image;
|
||||
Ellipse = GetTemplateChild(PART_Ellipse) as Ellipse;
|
||||
|
||||
UpdateInformation();
|
||||
}
|
||||
|
||||
private static void OnAddressInformationChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (obj is ImagePreviewControl control)
|
||||
control.UpdateInformation();
|
||||
}
|
||||
|
||||
private async void UpdateInformation()
|
||||
{
|
||||
if (KnownHostImage == null || InitialsGrid == null || InitialsTextblock == null || (string.IsNullOrEmpty(FromName) && string.IsNullOrEmpty(FromAddress)))
|
||||
return;
|
||||
|
||||
// Cancel active image loading if exists.
|
||||
if (!contactPictureLoadingCancellationTokenSource?.IsCancellationRequested ?? false)
|
||||
{
|
||||
get { return (string)GetValue(SenderContactPictureProperty); }
|
||||
set { SetValue(SenderContactPictureProperty, value); }
|
||||
contactPictureLoadingCancellationTokenSource.Cancel();
|
||||
}
|
||||
|
||||
public string FromName
|
||||
var host = ThumbnailService.GetHost(FromAddress);
|
||||
|
||||
bool isKnownHost = false;
|
||||
|
||||
if (!string.IsNullOrEmpty(host))
|
||||
{
|
||||
get { return (string)GetValue(FromNameProperty); }
|
||||
set { SetValue(FromNameProperty, value); }
|
||||
var tuple = ThumbnailService.CheckIsKnown(host);
|
||||
|
||||
isKnownHost = tuple.Item1;
|
||||
host = tuple.Item2;
|
||||
}
|
||||
|
||||
public string FromAddress
|
||||
if (isKnownHost)
|
||||
{
|
||||
get { return (string)GetValue(FromAddressProperty); }
|
||||
set { SetValue(FromAddressProperty, value); }
|
||||
// Unrealize others.
|
||||
|
||||
KnownHostImage.Visibility = Visibility.Visible;
|
||||
InitialsGrid.Visibility = Visibility.Collapsed;
|
||||
|
||||
// Apply company logo.
|
||||
KnownHostImage.Source = new BitmapImage(new Uri(ThumbnailService.GetKnownHostImage(host)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Ellipse Ellipse;
|
||||
private Grid InitialsGrid;
|
||||
private TextBlock InitialsTextblock;
|
||||
private Image KnownHostImage;
|
||||
private CancellationTokenSource contactPictureLoadingCancellationTokenSource;
|
||||
|
||||
public ImagePreviewControl()
|
||||
else
|
||||
{
|
||||
DefaultStyleKey = nameof(ImagePreviewControl);
|
||||
}
|
||||
KnownHostImage.Visibility = Visibility.Collapsed;
|
||||
InitialsGrid.Visibility = Visibility.Visible;
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
InitialsGrid = GetTemplateChild(PART_EllipseInitialsGrid) as Grid;
|
||||
InitialsTextblock = GetTemplateChild(PART_InitialsTextBlock) as TextBlock;
|
||||
KnownHostImage = GetTemplateChild(PART_KnownHostImage) as Image;
|
||||
Ellipse = GetTemplateChild(PART_Ellipse) as Ellipse;
|
||||
|
||||
UpdateInformation();
|
||||
}
|
||||
|
||||
private static void OnAddressInformationChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (obj is ImagePreviewControl control)
|
||||
control.UpdateInformation();
|
||||
}
|
||||
|
||||
private async void UpdateInformation()
|
||||
{
|
||||
if (KnownHostImage == null || InitialsGrid == null || InitialsTextblock == null || (string.IsNullOrEmpty(FromName) && string.IsNullOrEmpty(FromAddress)))
|
||||
return;
|
||||
|
||||
// Cancel active image loading if exists.
|
||||
if (!contactPictureLoadingCancellationTokenSource?.IsCancellationRequested ?? false)
|
||||
if (!string.IsNullOrEmpty(SenderContactPicture))
|
||||
{
|
||||
contactPictureLoadingCancellationTokenSource.Cancel();
|
||||
}
|
||||
contactPictureLoadingCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
var host = ThumbnailService.GetHost(FromAddress);
|
||||
try
|
||||
{
|
||||
var brush = await GetContactImageBrushAsync();
|
||||
|
||||
bool isKnownHost = false;
|
||||
|
||||
if (!string.IsNullOrEmpty(host))
|
||||
{
|
||||
var tuple = ThumbnailService.CheckIsKnown(host);
|
||||
|
||||
isKnownHost = tuple.Item1;
|
||||
host = tuple.Item2;
|
||||
}
|
||||
|
||||
if (isKnownHost)
|
||||
{
|
||||
// Unrealize others.
|
||||
|
||||
KnownHostImage.Visibility = Visibility.Visible;
|
||||
InitialsGrid.Visibility = Visibility.Collapsed;
|
||||
|
||||
// Apply company logo.
|
||||
KnownHostImage.Source = new BitmapImage(new Uri(ThumbnailService.GetKnownHostImage(host)));
|
||||
if (!contactPictureLoadingCancellationTokenSource?.Token.IsCancellationRequested ?? false)
|
||||
{
|
||||
Ellipse.Fill = brush;
|
||||
InitialsTextblock.Text = string.Empty;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Log exception.
|
||||
Debugger.Break();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
KnownHostImage.Visibility = Visibility.Collapsed;
|
||||
InitialsGrid.Visibility = Visibility.Visible;
|
||||
var colorHash = new ColorHash();
|
||||
var rgb = colorHash.Rgb(FromAddress);
|
||||
|
||||
if (!string.IsNullOrEmpty(SenderContactPicture))
|
||||
{
|
||||
contactPictureLoadingCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
try
|
||||
{
|
||||
var brush = await GetContactImageBrushAsync();
|
||||
|
||||
if (!contactPictureLoadingCancellationTokenSource?.Token.IsCancellationRequested ?? false)
|
||||
{
|
||||
Ellipse.Fill = brush;
|
||||
InitialsTextblock.Text = string.Empty;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Log exception.
|
||||
Debugger.Break();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var colorHash = new ColorHash();
|
||||
var rgb = colorHash.Rgb(FromAddress);
|
||||
|
||||
Ellipse.Fill = new SolidColorBrush(Color.FromArgb(rgb.A, rgb.R, rgb.G, rgb.B));
|
||||
InitialsTextblock.Text = ExtractInitialsFromName(FromName);
|
||||
}
|
||||
Ellipse.Fill = new SolidColorBrush(Color.FromArgb(rgb.A, rgb.R, rgb.G, rgb.B));
|
||||
InitialsTextblock.Text = ExtractInitialsFromName(FromName);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ImageBrush> GetContactImageBrushAsync()
|
||||
{
|
||||
// Load the image from base64 string.
|
||||
var bitmapImage = new BitmapImage();
|
||||
|
||||
var imageArray = Convert.FromBase64String(SenderContactPicture);
|
||||
var imageStream = new MemoryStream(imageArray);
|
||||
var randomAccessImageStream = imageStream.AsRandomAccessStream();
|
||||
|
||||
randomAccessImageStream.Seek(0);
|
||||
|
||||
|
||||
await bitmapImage.SetSourceAsync(randomAccessImageStream);
|
||||
|
||||
return new ImageBrush() { ImageSource = bitmapImage };
|
||||
}
|
||||
|
||||
public string ExtractInitialsFromName(string name)
|
||||
{
|
||||
// Change from name to from address in case of name doesn't exists.
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = FromAddress;
|
||||
}
|
||||
|
||||
// first remove all: punctuation, separator chars, control chars, and numbers (unicode style regexes)
|
||||
string initials = Regex.Replace(name, @"[\p{P}\p{S}\p{C}\p{N}]+", "");
|
||||
|
||||
// Replacing all possible whitespace/separator characters (unicode style), with a single, regular ascii space.
|
||||
initials = Regex.Replace(initials, @"\p{Z}+", " ");
|
||||
|
||||
// Remove all Sr, Jr, I, II, III, IV, V, VI, VII, VIII, IX at the end of names
|
||||
initials = Regex.Replace(initials.Trim(), @"\s+(?:[JS]R|I{1,3}|I[VX]|VI{0,3})$", "", RegexOptions.IgnoreCase);
|
||||
|
||||
// Extract up to 2 initials from the remaining cleaned name.
|
||||
initials = Regex.Replace(initials, @"^(\p{L})[^\s]*(?:\s+(?:\p{L}+\s+(?=\p{L}))?(?:(\p{L})\p{L}*)?)?$", "$1$2").Trim();
|
||||
|
||||
if (initials.Length > 2)
|
||||
{
|
||||
// Worst case scenario, everything failed, just grab the first two letters of what we have left.
|
||||
initials = initials.Substring(0, 2);
|
||||
}
|
||||
|
||||
return initials.ToUpperInvariant();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ImageBrush> GetContactImageBrushAsync()
|
||||
{
|
||||
// Load the image from base64 string.
|
||||
var bitmapImage = new BitmapImage();
|
||||
|
||||
var imageArray = Convert.FromBase64String(SenderContactPicture);
|
||||
var imageStream = new MemoryStream(imageArray);
|
||||
var randomAccessImageStream = imageStream.AsRandomAccessStream();
|
||||
|
||||
randomAccessImageStream.Seek(0);
|
||||
|
||||
|
||||
await bitmapImage.SetSourceAsync(randomAccessImageStream);
|
||||
|
||||
return new ImageBrush() { ImageSource = bitmapImage };
|
||||
}
|
||||
|
||||
public string ExtractInitialsFromName(string name)
|
||||
{
|
||||
// Change from name to from address in case of name doesn't exists.
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = FromAddress;
|
||||
}
|
||||
|
||||
// first remove all: punctuation, separator chars, control chars, and numbers (unicode style regexes)
|
||||
string initials = Regex.Replace(name, @"[\p{P}\p{S}\p{C}\p{N}]+", "");
|
||||
|
||||
// Replacing all possible whitespace/separator characters (unicode style), with a single, regular ascii space.
|
||||
initials = Regex.Replace(initials, @"\p{Z}+", " ");
|
||||
|
||||
// Remove all Sr, Jr, I, II, III, IV, V, VI, VII, VIII, IX at the end of names
|
||||
initials = Regex.Replace(initials.Trim(), @"\s+(?:[JS]R|I{1,3}|I[VX]|VI{0,3})$", "", RegexOptions.IgnoreCase);
|
||||
|
||||
// Extract up to 2 initials from the remaining cleaned name.
|
||||
initials = Regex.Replace(initials, @"^(\p{L})[^\s]*(?:\s+(?:\p{L}+\s+(?=\p{L}))?(?:(\p{L})\p{L}*)?)?$", "$1$2").Trim();
|
||||
|
||||
if (initials.Length > 2)
|
||||
{
|
||||
// Worst case scenario, everything failed, just grab the first two letters of what we have left.
|
||||
initials = initials.Substring(0, 2);
|
||||
}
|
||||
|
||||
return initials.ToUpperInvariant();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,200 +10,199 @@ using Wino.Core.Domain.Models.MailItem;
|
||||
using Wino.Extensions;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
|
||||
namespace Wino.Controls
|
||||
namespace Wino.Controls;
|
||||
|
||||
public sealed partial class MailItemDisplayInformationControl : UserControl
|
||||
{
|
||||
public sealed partial class MailItemDisplayInformationControl : UserControl
|
||||
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));
|
||||
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(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));
|
||||
public static readonly DependencyProperty HoverActionExecutedCommandProperty = DependencyProperty.Register(nameof(HoverActionExecutedCommand), typeof(ICommand), typeof(MailItemDisplayInformationControl), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty MailItemProperty = DependencyProperty.Register(nameof(MailItem), typeof(IMailItem), typeof(MailItemDisplayInformationControl), new PropertyMetadata(null, new PropertyChangedCallback(OnMailItemChanged)));
|
||||
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
|
||||
{
|
||||
public ImagePreviewControl GetImagePreviewControl() => ContactImage;
|
||||
get { return (bool)GetValue(IsThreadExpandedProperty); }
|
||||
set { SetValue(IsThreadExpandedProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsRunningHoverAction { get; set; }
|
||||
public bool IsThreadExpanderVisible
|
||||
{
|
||||
get { return (bool)GetValue(IsThreadExpanderVisibleProperty); }
|
||||
set { SetValue(IsThreadExpanderVisibleProperty, value); }
|
||||
}
|
||||
|
||||
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));
|
||||
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(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));
|
||||
public static readonly DependencyProperty HoverActionExecutedCommandProperty = DependencyProperty.Register(nameof(HoverActionExecutedCommand), typeof(ICommand), typeof(MailItemDisplayInformationControl), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty MailItemProperty = DependencyProperty.Register(nameof(MailItem), typeof(IMailItem), typeof(MailItemDisplayInformationControl), new PropertyMetadata(null, new PropertyChangedCallback(OnMailItemChanged)));
|
||||
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 Prefer24HourTimeFormat
|
||||
{
|
||||
get { return (bool)GetValue(Prefer24HourTimeFormatProperty); }
|
||||
set { SetValue(Prefer24HourTimeFormatProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsThreadExpanded
|
||||
public bool IsHoverActionsEnabled
|
||||
{
|
||||
get { return (bool)GetValue(IsHoverActionsEnabledProperty); }
|
||||
set { SetValue(IsHoverActionsEnabledProperty, value); }
|
||||
}
|
||||
|
||||
public IMailItem MailItem
|
||||
{
|
||||
get { return (IMailItem)GetValue(MailItemProperty); }
|
||||
set { SetValue(MailItemProperty, value); }
|
||||
}
|
||||
|
||||
public ICommand HoverActionExecutedCommand
|
||||
{
|
||||
get { return (ICommand)GetValue(HoverActionExecutedCommandProperty); }
|
||||
set { SetValue(HoverActionExecutedCommandProperty, value); }
|
||||
}
|
||||
|
||||
public MailOperation LeftHoverAction
|
||||
{
|
||||
get { return (MailOperation)GetValue(LeftHoverActionProperty); }
|
||||
set { SetValue(LeftHoverActionProperty, value); }
|
||||
}
|
||||
|
||||
public MailOperation CenterHoverAction
|
||||
{
|
||||
get { return (MailOperation)GetValue(CenterHoverActionProperty); }
|
||||
set { SetValue(CenterHoverActionProperty, value); }
|
||||
}
|
||||
|
||||
public MailOperation RightHoverAction
|
||||
{
|
||||
get { return (MailOperation)GetValue(RightHoverActionProperty); }
|
||||
set { SetValue(RightHoverActionProperty, value); }
|
||||
}
|
||||
|
||||
public WinoExpander ConnectedExpander
|
||||
{
|
||||
get { return (WinoExpander)GetValue(ConnectedExpanderProperty); }
|
||||
set { SetValue(ConnectedExpanderProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsSubjectVisible
|
||||
{
|
||||
get { return (bool)GetValue(IsSubjectVisibleProperty); }
|
||||
set { SetValue(IsSubjectVisibleProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsAvatarVisible
|
||||
{
|
||||
get { return (bool)GetValue(IsAvatarVisibleProperty); }
|
||||
set { SetValue(IsAvatarVisibleProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsCustomFocused
|
||||
{
|
||||
get { return (bool)GetValue(IsCustomFocusedProperty); }
|
||||
set { SetValue(IsCustomFocusedProperty, value); }
|
||||
}
|
||||
|
||||
public bool ShowPreviewText
|
||||
{
|
||||
get { return (bool)GetValue(ShowPreviewTextProperty); }
|
||||
set { SetValue(ShowPreviewTextProperty, value); }
|
||||
}
|
||||
|
||||
public MailListDisplayMode DisplayMode
|
||||
{
|
||||
get { return (MailListDisplayMode)GetValue(DisplayModeProperty); }
|
||||
set { SetValue(DisplayModeProperty, value); }
|
||||
}
|
||||
|
||||
public MailItemDisplayInformationControl()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
var compositor = this.Visual().Compositor;
|
||||
|
||||
var leftBackgroundVisual = compositor.CreateSpriteVisual();
|
||||
RootContainerVisualWrapper.SetChildVisual(leftBackgroundVisual);
|
||||
MainContentContainer.EnableImplicitAnimation(VisualPropertyType.Offset, 400);
|
||||
|
||||
RootContainer.EnableImplicitAnimation(VisualPropertyType.Offset, 400);
|
||||
ContentGrid.EnableImplicitAnimation(VisualPropertyType.Offset, 400);
|
||||
ContentStackpanel.EnableImplicitAnimation(VisualPropertyType.Offset, 400);
|
||||
IconsContainer.EnableImplicitAnimation(VisualPropertyType.Offset, 400);
|
||||
|
||||
RootContainerVisualWrapper.SizeChanged += (s, e) => leftBackgroundVisual.Size = e.NewSize.ToVector2();
|
||||
}
|
||||
|
||||
private static void OnMailItemChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (obj is MailItemDisplayInformationControl control)
|
||||
{
|
||||
get { return (bool)GetValue(IsThreadExpandedProperty); }
|
||||
set { SetValue(IsThreadExpandedProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsThreadExpanderVisible
|
||||
{
|
||||
get { return (bool)GetValue(IsThreadExpanderVisibleProperty); }
|
||||
set { SetValue(IsThreadExpanderVisibleProperty, value); }
|
||||
}
|
||||
|
||||
public bool Prefer24HourTimeFormat
|
||||
{
|
||||
get { return (bool)GetValue(Prefer24HourTimeFormatProperty); }
|
||||
set { SetValue(Prefer24HourTimeFormatProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsHoverActionsEnabled
|
||||
{
|
||||
get { return (bool)GetValue(IsHoverActionsEnabledProperty); }
|
||||
set { SetValue(IsHoverActionsEnabledProperty, value); }
|
||||
}
|
||||
|
||||
public IMailItem MailItem
|
||||
{
|
||||
get { return (IMailItem)GetValue(MailItemProperty); }
|
||||
set { SetValue(MailItemProperty, value); }
|
||||
}
|
||||
|
||||
public ICommand HoverActionExecutedCommand
|
||||
{
|
||||
get { return (ICommand)GetValue(HoverActionExecutedCommandProperty); }
|
||||
set { SetValue(HoverActionExecutedCommandProperty, value); }
|
||||
}
|
||||
|
||||
public MailOperation LeftHoverAction
|
||||
{
|
||||
get { return (MailOperation)GetValue(LeftHoverActionProperty); }
|
||||
set { SetValue(LeftHoverActionProperty, value); }
|
||||
}
|
||||
|
||||
public MailOperation CenterHoverAction
|
||||
{
|
||||
get { return (MailOperation)GetValue(CenterHoverActionProperty); }
|
||||
set { SetValue(CenterHoverActionProperty, value); }
|
||||
}
|
||||
|
||||
public MailOperation RightHoverAction
|
||||
{
|
||||
get { return (MailOperation)GetValue(RightHoverActionProperty); }
|
||||
set { SetValue(RightHoverActionProperty, value); }
|
||||
}
|
||||
|
||||
public WinoExpander ConnectedExpander
|
||||
{
|
||||
get { return (WinoExpander)GetValue(ConnectedExpanderProperty); }
|
||||
set { SetValue(ConnectedExpanderProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsSubjectVisible
|
||||
{
|
||||
get { return (bool)GetValue(IsSubjectVisibleProperty); }
|
||||
set { SetValue(IsSubjectVisibleProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsAvatarVisible
|
||||
{
|
||||
get { return (bool)GetValue(IsAvatarVisibleProperty); }
|
||||
set { SetValue(IsAvatarVisibleProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsCustomFocused
|
||||
{
|
||||
get { return (bool)GetValue(IsCustomFocusedProperty); }
|
||||
set { SetValue(IsCustomFocusedProperty, value); }
|
||||
}
|
||||
|
||||
public bool ShowPreviewText
|
||||
{
|
||||
get { return (bool)GetValue(ShowPreviewTextProperty); }
|
||||
set { SetValue(ShowPreviewTextProperty, value); }
|
||||
}
|
||||
|
||||
public MailListDisplayMode DisplayMode
|
||||
{
|
||||
get { return (MailListDisplayMode)GetValue(DisplayModeProperty); }
|
||||
set { SetValue(DisplayModeProperty, value); }
|
||||
}
|
||||
|
||||
public MailItemDisplayInformationControl()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
var compositor = this.Visual().Compositor;
|
||||
|
||||
var leftBackgroundVisual = compositor.CreateSpriteVisual();
|
||||
RootContainerVisualWrapper.SetChildVisual(leftBackgroundVisual);
|
||||
MainContentContainer.EnableImplicitAnimation(VisualPropertyType.Offset, 400);
|
||||
|
||||
RootContainer.EnableImplicitAnimation(VisualPropertyType.Offset, 400);
|
||||
ContentGrid.EnableImplicitAnimation(VisualPropertyType.Offset, 400);
|
||||
ContentStackpanel.EnableImplicitAnimation(VisualPropertyType.Offset, 400);
|
||||
IconsContainer.EnableImplicitAnimation(VisualPropertyType.Offset, 400);
|
||||
|
||||
RootContainerVisualWrapper.SizeChanged += (s, e) => leftBackgroundVisual.Size = e.NewSize.ToVector2();
|
||||
}
|
||||
|
||||
private static void OnMailItemChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (obj is MailItemDisplayInformationControl control)
|
||||
{
|
||||
control.UpdateInformation();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateInformation()
|
||||
{
|
||||
if (MailItem == null) return;
|
||||
|
||||
TitleText.Text = string.IsNullOrWhiteSpace(MailItem.Subject) ? Translator.MailItemNoSubject : MailItem.Subject;
|
||||
}
|
||||
|
||||
private void ControlPointerEntered(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
if (IsHoverActionsEnabled)
|
||||
{
|
||||
HoverActionButtons.Visibility = Visibility.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
private void ControlPointerExited(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
if (IsHoverActionsEnabled)
|
||||
{
|
||||
HoverActionButtons.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
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<MailItemViewModel>().Select(a => a.MailCopy), toggleExecution: true);
|
||||
|
||||
if (package == null) return;
|
||||
|
||||
HoverActionExecutedCommand?.Execute(package);
|
||||
}
|
||||
|
||||
private void FirstActionClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ExecuteHoverAction(LeftHoverAction);
|
||||
}
|
||||
|
||||
private void SecondActionClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ExecuteHoverAction(CenterHoverAction);
|
||||
}
|
||||
|
||||
private void ThirdActionClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ExecuteHoverAction(RightHoverAction);
|
||||
control.UpdateInformation();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateInformation()
|
||||
{
|
||||
if (MailItem == null) return;
|
||||
|
||||
TitleText.Text = string.IsNullOrWhiteSpace(MailItem.Subject) ? Translator.MailItemNoSubject : MailItem.Subject;
|
||||
}
|
||||
|
||||
private void ControlPointerEntered(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
if (IsHoverActionsEnabled)
|
||||
{
|
||||
HoverActionButtons.Visibility = Visibility.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
private void ControlPointerExited(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
if (IsHoverActionsEnabled)
|
||||
{
|
||||
HoverActionButtons.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
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<MailItemViewModel>().Select(a => a.MailCopy), toggleExecution: true);
|
||||
|
||||
if (package == null) return;
|
||||
|
||||
HoverActionExecutedCommand?.Execute(package);
|
||||
}
|
||||
|
||||
private void FirstActionClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ExecuteHoverAction(LeftHoverAction);
|
||||
}
|
||||
|
||||
private void SecondActionClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ExecuteHoverAction(CenterHoverAction);
|
||||
}
|
||||
|
||||
private void ThirdActionClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ExecuteHoverAction(RightHoverAction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,71 +3,70 @@ using System.Windows.Input;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Wino.Controls
|
||||
namespace Wino.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// Templated button for each setting in Settings Dialog.
|
||||
/// </summary>
|
||||
public partial class SettingsMenuItemControl : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// Templated button for each setting in Settings Dialog.
|
||||
/// </summary>
|
||||
public partial class SettingsMenuItemControl : Control
|
||||
public string Title
|
||||
{
|
||||
public string Title
|
||||
{
|
||||
get { return (string)GetValue(TitleProperty); }
|
||||
set { SetValue(TitleProperty, value); }
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get { return (string)GetValue(DescriptionProperty); }
|
||||
set { SetValue(DescriptionProperty, value); }
|
||||
}
|
||||
|
||||
public FrameworkElement Icon
|
||||
{
|
||||
get { return (FrameworkElement)GetValue(IconProperty); }
|
||||
set { SetValue(IconProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
public ICommand Command
|
||||
{
|
||||
get { return (ICommand)GetValue(CommandProperty); }
|
||||
set { SetValue(CommandProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
|
||||
public object CommandParameter
|
||||
{
|
||||
get { return (object)GetValue(CommandParameterProperty); }
|
||||
set { SetValue(CommandParameterProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsClickable
|
||||
{
|
||||
get { return (bool)GetValue(IsClickableProperty); }
|
||||
set { SetValue(IsClickableProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsNavigateIconVisible
|
||||
{
|
||||
get { return (bool)GetValue(IsNavigateIconVisibleProperty); }
|
||||
set { SetValue(IsNavigateIconVisibleProperty, value); }
|
||||
}
|
||||
|
||||
public FrameworkElement SideContent
|
||||
{
|
||||
get { return (FrameworkElement)GetValue(SideContentProperty); }
|
||||
set { SetValue(SideContentProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(nameof(CommandParameter), typeof(object), typeof(SettingsMenuItemControl), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty SideContentProperty = DependencyProperty.Register(nameof(SideContent), typeof(FrameworkElement), typeof(SettingsMenuItemControl), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty IsClickableProperty = DependencyProperty.Register(nameof(IsClickable), typeof(bool), typeof(SettingsMenuItemControl), new PropertyMetadata(true));
|
||||
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(SettingsMenuItemControl), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty IconProperty = DependencyProperty.Register(nameof(Icon), typeof(FrameworkElement), typeof(SettingsMenuItemControl), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(nameof(Description), typeof(string), typeof(SettingsMenuItemControl), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(SettingsMenuItemControl), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty IsNavigateIconVisibleProperty = DependencyProperty.Register(nameof(IsNavigateIconVisible), typeof(bool), typeof(SettingsMenuItemControl), new PropertyMetadata(true));
|
||||
get { return (string)GetValue(TitleProperty); }
|
||||
set { SetValue(TitleProperty, value); }
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get { return (string)GetValue(DescriptionProperty); }
|
||||
set { SetValue(DescriptionProperty, value); }
|
||||
}
|
||||
|
||||
public FrameworkElement Icon
|
||||
{
|
||||
get { return (FrameworkElement)GetValue(IconProperty); }
|
||||
set { SetValue(IconProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
public ICommand Command
|
||||
{
|
||||
get { return (ICommand)GetValue(CommandProperty); }
|
||||
set { SetValue(CommandProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
|
||||
public object CommandParameter
|
||||
{
|
||||
get { return (object)GetValue(CommandParameterProperty); }
|
||||
set { SetValue(CommandParameterProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsClickable
|
||||
{
|
||||
get { return (bool)GetValue(IsClickableProperty); }
|
||||
set { SetValue(IsClickableProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsNavigateIconVisible
|
||||
{
|
||||
get { return (bool)GetValue(IsNavigateIconVisibleProperty); }
|
||||
set { SetValue(IsNavigateIconVisibleProperty, value); }
|
||||
}
|
||||
|
||||
public FrameworkElement SideContent
|
||||
{
|
||||
get { return (FrameworkElement)GetValue(SideContentProperty); }
|
||||
set { SetValue(SideContentProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(nameof(CommandParameter), typeof(object), typeof(SettingsMenuItemControl), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty SideContentProperty = DependencyProperty.Register(nameof(SideContent), typeof(FrameworkElement), typeof(SettingsMenuItemControl), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty IsClickableProperty = DependencyProperty.Register(nameof(IsClickable), typeof(bool), typeof(SettingsMenuItemControl), new PropertyMetadata(true));
|
||||
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(SettingsMenuItemControl), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty IconProperty = DependencyProperty.Register(nameof(Icon), typeof(FrameworkElement), typeof(SettingsMenuItemControl), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(nameof(Description), typeof(string), typeof(SettingsMenuItemControl), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(SettingsMenuItemControl), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty IsNavigateIconVisibleProperty = DependencyProperty.Register(nameof(IsNavigateIconVisible), typeof(bool), typeof(SettingsMenuItemControl), new PropertyMetadata(true));
|
||||
}
|
||||
|
||||
@@ -4,126 +4,125 @@ using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Hosting;
|
||||
using Windows.UI.Xaml.Markup;
|
||||
|
||||
namespace Wino.Controls
|
||||
namespace Wino.Controls;
|
||||
|
||||
[ContentProperty(Name = nameof(Content))]
|
||||
public partial class WinoExpander : Control
|
||||
{
|
||||
[ContentProperty(Name = nameof(Content))]
|
||||
public partial 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 static readonly DependencyProperty TemplateSettingsProperty = DependencyProperty.Register(nameof(TemplateSettings), typeof(WinoExpanderTemplateSettings), typeof(WinoExpander), new PropertyMetadata(new WinoExpanderTemplateSettings()));
|
||||
|
||||
public UIElement Content
|
||||
{
|
||||
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 static readonly DependencyProperty TemplateSettingsProperty = DependencyProperty.Register(nameof(TemplateSettings), typeof(WinoExpanderTemplateSettings), typeof(WinoExpander), new PropertyMetadata(new WinoExpanderTemplateSettings()));
|
||||
|
||||
public UIElement Content
|
||||
{
|
||||
get { return (UIElement)GetValue(ContentProperty); }
|
||||
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)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
get { return (UIElement)GetValue(ContentProperty); }
|
||||
set { SetValue(ContentProperty, value); }
|
||||
}
|
||||
|
||||
#region Settings
|
||||
|
||||
public class WinoExpanderTemplateSettings : DependencyObject
|
||||
public WinoExpanderTemplateSettings TemplateSettings
|
||||
{
|
||||
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); }
|
||||
}
|
||||
get { return (WinoExpanderTemplateSettings)GetValue(TemplateSettingsProperty); }
|
||||
set { SetValue(TemplateSettingsProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
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)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
@@ -6,77 +6,76 @@ using Wino.Core.Domain.Models.MailItem;
|
||||
using Wino.Helpers;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
|
||||
namespace Wino.Controls
|
||||
namespace Wino.Controls;
|
||||
|
||||
public partial class WinoSwipeControlItems : SwipeItems
|
||||
{
|
||||
public partial class WinoSwipeControlItems : SwipeItems
|
||||
public static readonly DependencyProperty SwipeOperationProperty = DependencyProperty.Register(nameof(SwipeOperation), typeof(MailOperation), typeof(WinoSwipeControlItems), new PropertyMetadata(default(MailOperation), new PropertyChangedCallback(OnItemsChanged)));
|
||||
public static readonly DependencyProperty MailItemProperty = DependencyProperty.Register(nameof(MailItem), typeof(IMailItem), typeof(WinoSwipeControlItems), new PropertyMetadata(null));
|
||||
|
||||
public IMailItem MailItem
|
||||
{
|
||||
public static readonly DependencyProperty SwipeOperationProperty = DependencyProperty.Register(nameof(SwipeOperation), typeof(MailOperation), typeof(WinoSwipeControlItems), new PropertyMetadata(default(MailOperation), new PropertyChangedCallback(OnItemsChanged)));
|
||||
public static readonly DependencyProperty MailItemProperty = DependencyProperty.Register(nameof(MailItem), typeof(IMailItem), typeof(WinoSwipeControlItems), new PropertyMetadata(null));
|
||||
get { return (IMailItem)GetValue(MailItemProperty); }
|
||||
set { SetValue(MailItemProperty, value); }
|
||||
}
|
||||
|
||||
public IMailItem MailItem
|
||||
|
||||
public MailOperation SwipeOperation
|
||||
{
|
||||
get { return (MailOperation)GetValue(SwipeOperationProperty); }
|
||||
set { SetValue(SwipeOperationProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnItemsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (obj is WinoSwipeControlItems control)
|
||||
{
|
||||
get { return (IMailItem)GetValue(MailItemProperty); }
|
||||
set { SetValue(MailItemProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
public MailOperation SwipeOperation
|
||||
{
|
||||
get { return (MailOperation)GetValue(SwipeOperationProperty); }
|
||||
set { SetValue(SwipeOperationProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnItemsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (obj is WinoSwipeControlItems control)
|
||||
{
|
||||
control.BuildSwipeItems();
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildSwipeItems()
|
||||
{
|
||||
this.Clear();
|
||||
|
||||
var swipeItem = GetSwipeItem(SwipeOperation);
|
||||
|
||||
this.Add(swipeItem);
|
||||
}
|
||||
|
||||
private SwipeItem GetSwipeItem(MailOperation operation)
|
||||
{
|
||||
if (MailItem == null) return null;
|
||||
|
||||
var finalOperation = operation;
|
||||
|
||||
bool isSingleItem = MailItem is MailItemViewModel;
|
||||
|
||||
if (isSingleItem)
|
||||
{
|
||||
var singleItem = MailItem as MailItemViewModel;
|
||||
|
||||
if (operation == MailOperation.MarkAsRead && singleItem.IsRead)
|
||||
finalOperation = MailOperation.MarkAsUnread;
|
||||
else if (operation == MailOperation.MarkAsUnread && !singleItem.IsRead)
|
||||
finalOperation = MailOperation.MarkAsRead;
|
||||
}
|
||||
else
|
||||
{
|
||||
var threadItem = MailItem as ThreadMailItemViewModel;
|
||||
|
||||
if (operation == MailOperation.MarkAsRead && threadItem.ThreadItems.All(a => a.IsRead))
|
||||
finalOperation = MailOperation.MarkAsUnread;
|
||||
else if (operation == MailOperation.MarkAsUnread && threadItem.ThreadItems.All(a => !a.IsRead))
|
||||
finalOperation = MailOperation.MarkAsRead;
|
||||
}
|
||||
|
||||
var item = new SwipeItem()
|
||||
{
|
||||
IconSource = new WinoFontIconSource() { Icon = XamlHelpers.GetWinoIconGlyph(finalOperation) },
|
||||
Text = XamlHelpers.GetOperationString(finalOperation),
|
||||
};
|
||||
|
||||
return item;
|
||||
control.BuildSwipeItems();
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildSwipeItems()
|
||||
{
|
||||
this.Clear();
|
||||
|
||||
var swipeItem = GetSwipeItem(SwipeOperation);
|
||||
|
||||
this.Add(swipeItem);
|
||||
}
|
||||
|
||||
private SwipeItem GetSwipeItem(MailOperation operation)
|
||||
{
|
||||
if (MailItem == null) return null;
|
||||
|
||||
var finalOperation = operation;
|
||||
|
||||
bool isSingleItem = MailItem is MailItemViewModel;
|
||||
|
||||
if (isSingleItem)
|
||||
{
|
||||
var singleItem = MailItem as MailItemViewModel;
|
||||
|
||||
if (operation == MailOperation.MarkAsRead && singleItem.IsRead)
|
||||
finalOperation = MailOperation.MarkAsUnread;
|
||||
else if (operation == MailOperation.MarkAsUnread && !singleItem.IsRead)
|
||||
finalOperation = MailOperation.MarkAsRead;
|
||||
}
|
||||
else
|
||||
{
|
||||
var threadItem = MailItem as ThreadMailItemViewModel;
|
||||
|
||||
if (operation == MailOperation.MarkAsRead && threadItem.ThreadItems.All(a => a.IsRead))
|
||||
finalOperation = MailOperation.MarkAsUnread;
|
||||
else if (operation == MailOperation.MarkAsUnread && threadItem.ThreadItems.All(a => !a.IsRead))
|
||||
finalOperation = MailOperation.MarkAsRead;
|
||||
}
|
||||
|
||||
var item = new SwipeItem()
|
||||
{
|
||||
IconSource = new WinoFontIconSource() { Icon = XamlHelpers.GetWinoIconGlyph(finalOperation) },
|
||||
Text = XamlHelpers.GetOperationString(finalOperation),
|
||||
};
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user