I don't know some changes....

This commit is contained in:
Burak Kaan Köse
2024-07-19 20:31:13 +02:00
parent 026151e7e4
commit 5b68f237f0
384 changed files with 176 additions and 29755 deletions

View File

@@ -1,80 +0,0 @@
using System.Numerics;
using Microsoft.UI.Xaml.Controls;
using Wino.Core.Domain.Interfaces;
#if NET8_0
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Shapes;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Shapes;
#endif
namespace Wino.Controls
{
public 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 IAccountMenuItem BindingData
{
get { return (IAccountMenuItem)GetValue(BindingDataProperty); }
set { SetValue(BindingDataProperty, value); }
}
private const string PART_NavigationViewItemMenuItemsHost = "NavigationViewItemMenuItemsHost";
private const string PART_SelectionIndicator = "CustomSelectionIndicator";
private ItemsRepeater _itemsRepeater;
private Rectangle _selectionIndicator;
public AccountNavigationItem()
{
DefaultStyleKey = typeof(AccountNavigationItem);
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
_itemsRepeater = GetTemplateChild(PART_NavigationViewItemMenuItemsHost) as ItemsRepeater;
_selectionIndicator = GetTemplateChild(PART_SelectionIndicator) as Rectangle;
if (_itemsRepeater == null) return;
(_itemsRepeater.Layout as StackLayout).Spacing = 0;
UpdateSelectionBorder();
}
private static void OnIsActiveAccountChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is AccountNavigationItem control)
control.UpdateSelectionBorder();
}
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;
}
}
}

View File

@@ -1,109 +0,0 @@
<UserControl
x:Class="Wino.Controls.Advanced.WinoAppTitleBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:advanced="using:Wino.Controls.Advanced"
xmlns:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals"
xmlns:animations="using:CommunityToolkit.WinUI.Animations"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Wino.Controls.Advanced"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
d:DesignHeight="300"
d:DesignWidth="400"
mc:Ignorable="d">
<Grid x:Name="MainGrid" Background="{ThemeResource AppBarBackgroundColor}">
<Grid
x:Name="dragbar"
Background="Transparent"
IsHitTestVisible="True" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="FluentButtonWidth" Width="Auto" />
<ColumnDefinition x:Name="EmptySpaceWidth" Width="*" />
<ColumnDefinition x:Name="SystemReservedWidth" Width="180" />
</Grid.ColumnDefinitions>
<!-- Shell Title Bar Left Side Background Placeholder -->
<Grid Grid.ColumnSpan="3" />
<!-- Menu + Back Button -->
<StackPanel
x:Name="LeftMenuStackPanel"
Orientation="Horizontal"
SizeChanged="TitlebarSizeChanged">
<Button
x:Name="PaneButton"
Width="48"
Margin="-2,-2,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Stretch"
Background="Transparent"
BorderBrush="Transparent"
Click="PaneClicked">
<muxc:AnimatedIcon Width="16">
<muxc:AnimatedIcon.Source>
<animatedvisuals:AnimatedGlobalNavigationButtonVisualSource />
</muxc:AnimatedIcon.Source>
<muxc:AnimatedIcon.FallbackIconSource>
<muxc:SymbolIconSource Symbol="GlobalNavigationButton" />
</muxc:AnimatedIcon.FallbackIconSource>
</muxc:AnimatedIcon>
</Button>
<Button
x:Name="BackButton"
Width="48"
Margin="-2,4,4,4"
HorizontalAlignment="Left"
VerticalAlignment="Stretch"
Background="Transparent"
BorderBrush="Transparent"
Click="BackClicked"
Visibility="{x:Bind IsBackButtonVisible, Mode=OneWay}">
<muxc:AnimatedIcon Width="16">
<muxc:AnimatedIcon.Source>
<animatedvisuals:AnimatedBackVisualSource />
</muxc:AnimatedIcon.Source>
<muxc:AnimatedIcon.FallbackIconSource>
<muxc:SymbolIconSource Symbol="Back" />
</muxc:AnimatedIcon.FallbackIconSource>
</muxc:AnimatedIcon>
</Button>
</StackPanel>
<!-- CoreWindow Title -->
<TextBlock
x:Name="CoreWindowTitleTextBlock"
Grid.Column="1"
Margin="4,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontWeight="SemiBold"
HorizontalTextAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind CoreWindowText, Mode=OneWay}"
TextTrimming="Clip">
<animations:Implicit.ShowAnimations>
<animations:OpacityAnimation
From="0"
To="1.0"
Duration="0:0:1" />
</animations:Implicit.ShowAnimations>
</TextBlock>
<!-- Shell Sub Content -->
<ContentPresenter
x:Name="ShellContentContainer"
Grid.Column="1"
Canvas.ZIndex="2"
Content="{x:Bind ShellFrameContent, Mode=OneWay}">
<ContentPresenter.ContentTransitions>
<TransitionCollection>
<PaneThemeTransition Edge="Top" />
</TransitionCollection>
</ContentPresenter.ContentTransitions>
</ContentPresenter>
</Grid>
</Grid>
</UserControl>

View File

@@ -1,175 +0,0 @@
using Windows.Foundation;
using Wino.Core.WinUI.Services;
using Microsoft.Extensions.DependencyInjection;
#if NET8_0
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
#endif
namespace Wino.Controls.Advanced
{
public sealed partial class WinoAppTitleBar : UserControl
{
private IAppShellService _appShellService = App.Current.Services.GetService<IAppShellService>();
public event TypedEventHandler<WinoAppTitleBar, RoutedEventArgs> BackButtonClicked;
public string CoreWindowText
{
get { return (string)GetValue(CoreWindowTextProperty); }
set { SetValue(CoreWindowTextProperty, value); }
}
public double SystemReserved
{
get { return (double)GetValue(SystemReservedProperty); }
set { SetValue(SystemReservedProperty, value); }
}
public UIElement ShellFrameContent
{
get { return (UIElement)GetValue(ShellFrameContentProperty); }
set { SetValue(ShellFrameContentProperty, value); }
}
public Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode NavigationViewDisplayMode
{
get { return (Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode)GetValue(NavigationViewDisplayModeProperty); }
set { SetValue(NavigationViewDisplayModeProperty, value); }
}
public bool IsNavigationPaneOpen
{
get { return (bool)GetValue(IsNavigationPaneOpenProperty); }
set { SetValue(IsNavigationPaneOpenProperty, value); }
}
public double OpenPaneLength
{
get { return (double)GetValue(OpenPaneLengthProperty); }
set { SetValue(OpenPaneLengthProperty, value); }
}
public bool IsBackButtonVisible
{
get { return (bool)GetValue(IsBackButtonVisibleProperty); }
set { SetValue(IsBackButtonVisibleProperty, value); }
}
public bool IsReaderNarrowed
{
get { return (bool)GetValue(IsReaderNarrowedProperty); }
set { SetValue(IsReaderNarrowedProperty, value); }
}
public bool IsRenderingPaneVisible
{
get { return (bool)GetValue(IsRenderingPaneVisibleProperty); }
set { SetValue(IsRenderingPaneVisibleProperty, value); }
}
public static readonly DependencyProperty IsRenderingPaneVisibleProperty = DependencyProperty.Register(nameof(IsRenderingPaneVisible), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(false, OnDrawingPropertyChanged));
public static readonly DependencyProperty IsReaderNarrowedProperty = DependencyProperty.Register(nameof(IsReaderNarrowed), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(false, OnIsReaderNarrowedChanged));
public static readonly DependencyProperty IsBackButtonVisibleProperty = DependencyProperty.Register(nameof(IsBackButtonVisible), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(false, OnDrawingPropertyChanged));
public static readonly DependencyProperty OpenPaneLengthProperty = DependencyProperty.Register(nameof(OpenPaneLength), typeof(double), typeof(WinoAppTitleBar), new PropertyMetadata(0d, OnDrawingPropertyChanged));
public static readonly DependencyProperty IsNavigationPaneOpenProperty = DependencyProperty.Register(nameof(IsNavigationPaneOpen), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(false, OnDrawingPropertyChanged));
public static readonly DependencyProperty NavigationViewDisplayModeProperty = DependencyProperty.Register(nameof(NavigationViewDisplayMode), typeof(Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode), typeof(WinoAppTitleBar), new PropertyMetadata(Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Compact, OnDrawingPropertyChanged));
public static readonly DependencyProperty ShellFrameContentProperty = DependencyProperty.Register(nameof(ShellFrameContent), typeof(UIElement), typeof(WinoAppTitleBar), new PropertyMetadata(null, OnDrawingPropertyChanged));
public static readonly DependencyProperty SystemReservedProperty = DependencyProperty.Register(nameof(SystemReserved), typeof(double), typeof(WinoAppTitleBar), new PropertyMetadata(0, OnDrawingPropertyChanged));
public static readonly DependencyProperty CoreWindowTextProperty = DependencyProperty.Register(nameof(CoreWindowText), typeof(string), typeof(WinoAppTitleBar), new PropertyMetadata(string.Empty, OnDrawingPropertyChanged));
public static readonly DependencyProperty ReadingPaneLengthProperty = DependencyProperty.Register(nameof(ReadingPaneLength), typeof(double), typeof(WinoAppTitleBar), new PropertyMetadata(420d, OnDrawingPropertyChanged));
public double ReadingPaneLength
{
get { return (double)GetValue(ReadingPaneLengthProperty); }
set { SetValue(ReadingPaneLengthProperty, value); }
}
private static void OnIsReaderNarrowedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is WinoAppTitleBar bar)
{
bar.DrawTitleBar();
}
}
private static void OnDrawingPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is WinoAppTitleBar bar)
{
bar.DrawTitleBar();
}
}
private void DrawTitleBar()
{
UpdateLayout();
CoreWindowTitleTextBlock.Visibility = Visibility.Collapsed;
ShellContentContainer.Width = double.NaN;
ShellContentContainer.Margin = new Thickness(0, 0, 0, 0);
ShellContentContainer.HorizontalAlignment = HorizontalAlignment.Stretch;
EmptySpaceWidth.Width = new GridLength(1, GridUnitType.Star);
// Menu is not visible.
if (NavigationViewDisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Minimal)
{
}
else if (NavigationViewDisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Compact)
{
// Icons are visible.
if (!IsReaderNarrowed)
{
ShellContentContainer.HorizontalAlignment = HorizontalAlignment.Left;
ShellContentContainer.Width = ReadingPaneLength;
}
}
else if (NavigationViewDisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Expanded)
{
if (IsNavigationPaneOpen)
{
CoreWindowTitleTextBlock.Visibility = Visibility.Visible;
// LMargin = OpenPaneLength - LeftMenuStackPanel
ShellContentContainer.Margin = new Thickness(OpenPaneLength - LeftMenuStackPanel.ActualSize.X, 0, 0, 0);
if (!IsReaderNarrowed)
{
ShellContentContainer.HorizontalAlignment = HorizontalAlignment.Left;
ShellContentContainer.Width = ReadingPaneLength;
}
}
else
{
EmptySpaceWidth.Width = new GridLength(ReadingPaneLength, GridUnitType.Pixel);
}
}
}
public WinoAppTitleBar()
{
InitializeComponent();
_appShellService.AppWindow.SetTitleBar(dragbar);
}
private void BackClicked(object sender, RoutedEventArgs e)
{
BackButtonClicked?.Invoke(this, e);
}
private void PaneClicked(object sender, RoutedEventArgs e)
{
IsNavigationPaneOpen = !IsNavigationPaneOpen;
}
private void TitlebarSizeChanged(object sender, SizeChangedEventArgs e) => DrawTitleBar();
}
}

View File

@@ -1,390 +0,0 @@
using System;
using System.Linq;
using System.Windows.Input;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.UI.Xaml.Controls;
using MoreLinq;
using Serilog;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Models.MailItem;
using Wino.Extensions;
using Wino.Mail.ViewModels.Data;
using Wino.Mail.ViewModels.Messages;
#if NET8_0
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Input;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
#endif
namespace Wino.Controls.Advanced
{
/// <summary>
/// Custom ListView control that handles multiple selection with Extended/Multiple selection mode
/// and supports threads.
/// </summary>
public class WinoListView : ListView, IDisposable
{
private ILogger logger = Log.ForContext<WinoListView>();
private const string PART_ScrollViewer = "ScrollViewer";
private ScrollViewer internalScrollviewer;
/// <summary>
/// Gets or sets whether this ListView belongs to thread items.
/// This is important for detecting selected items etc.
/// </summary>
public bool IsThreadListView
{
get { return (bool)GetValue(IsThreadListViewProperty); }
set { SetValue(IsThreadListViewProperty, value); }
}
public ICommand ItemDeletedCommand
{
get { return (ICommand)GetValue(ItemDeletedCommandProperty); }
set { SetValue(ItemDeletedCommandProperty, value); }
}
public ICommand LoadMoreCommand
{
get { return (ICommand)GetValue(LoadMoreCommandProperty); }
set { SetValue(LoadMoreCommandProperty, value); }
}
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 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;
ItemClick += MailItemClicked;
ProcessKeyboardAccelerators += ProcessDelKey;
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
internalScrollviewer = GetTemplateChild(PART_ScrollViewer) as ScrollViewer;
if (internalScrollviewer == null)
{
logger.Warning("WinoListView does not have an internal ScrollViewer. Infinite scrolling behavior might be effected.");
return;
}
internalScrollviewer.ViewChanged -= InternalScrollVeiwerViewChanged;
internalScrollviewer.ViewChanged += InternalScrollVeiwerViewChanged;
}
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)
{
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);
}
}
}
private void ProcessDelKey(UIElement sender, ProcessKeyboardAcceleratorEventArgs args)
{
if (args.Key == Windows.System.VirtualKey.Delete)
{
args.Handled = true;
ItemDeletedCommand?.Execute((int)MailOperation.SoftDelete);
}
}
private void ItemDragCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
{
if (args.Items.Any(a => a is MailItemViewModel))
{
args.Items.Cast<MailItemViewModel>().ForEach(a => a.IsCustomFocused = false);
}
}
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)
{
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);
}
}
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;
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.SelectedItems.Contains(exceptViewModel))
{
if (!preserveThreadExpanding)
{
c.IsThreadExpanded = false;
}
threadListView.SelectedItems.Clear();
}
}
else
{
if (!preserveThreadExpanding)
{
c.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));
}
}
}
if (e.AddedItems != null)
{
foreach (var addedItem in e.AddedItems)
{
if (addedItem is MailItemViewModel addedMailItemViewModel)
{
// Mail item selected.
addedMailItemViewModel.IsSelected = true;
WeakReferenceMessenger.Default.Send(new MailItemSelectedEvent(addedMailItemViewModel));
}
else if (addedItem is ThreadMailItemViewModel threadMailItemViewModel)
{
threadMailItemViewModel.IsThreadExpanded = true;
// Don't select thread containers.
SelectedItems.Remove(addedItem);
}
}
}
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 =>
{
// c.IsThreadExpanded = false;
var threadListView = GetThreadInternalListView(c);
threadListView?.SelectedItems.Clear();
});
}
}
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));
}
}
}
}
private WinoListView GetThreadInternalListView(ThreadMailItemViewModel threadMailItemViewModel)
{
var itemContainer = ContainerFromItem(threadMailItemViewModel);
if (itemContainer is ListViewItem listItem)
{
var expander = listItem.GetChildByName<Expander>("ThreadExpander");
if (expander != null)
return expander.Content as WinoListView;
}
return null;
}
public void Dispose()
{
DragItemsCompleted -= ItemDragCompleted;
DragItemsStarting -= ItemDragStarting;
SelectionChanged -= SelectedItemsChanged;
ItemClick -= MailItemClicked;
ProcessKeyboardAccelerators -= ProcessDelKey;
if (internalScrollviewer != null)
{
internalScrollviewer.ViewChanged -= InternalScrollVeiwerViewChanged;
}
}
}
}

View File

@@ -1,68 +0,0 @@
using System.Collections.Generic;
namespace Wino.Controls
{
public static class ControlConstants
{
public static Dictionary<WinoIconGlyph, string> WinoIconFontDictionary = new Dictionary<WinoIconGlyph, string>()
{
{ WinoIconGlyph.None, "\u0020" },
{ WinoIconGlyph.Archive, "\uE066" },
{ WinoIconGlyph.UnArchive, "\uE06C" },
{ WinoIconGlyph.Reply, "\uF176" },
{ WinoIconGlyph.ReplyAll, "\uF17A" },
{ WinoIconGlyph.Sync, "\uE902" },
{ WinoIconGlyph.Send, "\uEA8E" },
{ WinoIconGlyph.LightEditor, "\uE1F6" },
{ WinoIconGlyph.Delete, "\uEEA6" },
{ WinoIconGlyph.DarkEditor, "\uEE44" },
{ WinoIconGlyph.Draft, "\uF3BE" },
{ WinoIconGlyph.Flag, "\uF40C" },
{ WinoIconGlyph.ClearFlag, "\uF40F" },
{ WinoIconGlyph.Folder, "\uE643" },
{ WinoIconGlyph.Forward, "\uE7AA" },
{ WinoIconGlyph.Inbox, "\uF516" },
{ WinoIconGlyph.MarkRead, "\uF522" },
{ WinoIconGlyph.MarkUnread, "\uF529" },
{ WinoIconGlyph.MultiSelect, "\uE84D" },
{ WinoIconGlyph.Save, "\uEA43" },
{ WinoIconGlyph.CreateFolder, "\uE645" },
{ WinoIconGlyph.Pin, "\uF5FF" },
{ WinoIconGlyph.UnPin, "\uE985" },
{ WinoIconGlyph.Star, "\uF70D" },
{ WinoIconGlyph.Ignore, "\uF5D0" },
{ WinoIconGlyph.Junk, "\uE903" },
{ WinoIconGlyph.Find, "\uEA7D" },
{ WinoIconGlyph.Zoom, "\uEE8E" },
{ WinoIconGlyph.SpecialFolderInbox, "\uF516" },
{ WinoIconGlyph.SpecialFolderStarred, "\uF70D" },
{ WinoIconGlyph.SpecialFolderImportant, "\uE2F4" },
{ WinoIconGlyph.SpecialFolderSent, "\uEA8E" },
{ WinoIconGlyph.SpecialFolderDraft, "\uF3BE" },
{ WinoIconGlyph.SpecialFolderArchive, "\uE066" },
{ WinoIconGlyph.SpecialFolderDeleted, "\uEEA6" },
{ WinoIconGlyph.SpecialFolderJunk, "\uE903" },
{ WinoIconGlyph.SpecialFolderChat, "\uE2E3" },
{ WinoIconGlyph.SpecialFolderCategory, "\uF599" },
{ WinoIconGlyph.SpecialFolderUnread, "\uF529" },
{ WinoIconGlyph.SpecialFolderForums, "\uF5B8" },
{ WinoIconGlyph.SpecialFolderUpdated, "\uF565" },
{ WinoIconGlyph.SpecialFolderPersonal, "\uE25A" },
{ WinoIconGlyph.SpecialFolderPromotions, "\uF7B6" },
{ WinoIconGlyph.SpecialFolderSocial, "\uEEEB" },
{ WinoIconGlyph.SpecialFolderOther, "\uE643" },
{ WinoIconGlyph.SpecialFolderMore, "\uF0F4" },
{ WinoIconGlyph.Microsoft, "\uE900" },
{ WinoIconGlyph.Google, "\uE901" },
{ WinoIconGlyph.NewMail, "\uF107" },
{ WinoIconGlyph.TurnOfNotifications, "\uF11D" },
{ WinoIconGlyph.Rename, "\uF668" },
{ WinoIconGlyph.EmptyFolder, "\uE47E" },
{ WinoIconGlyph.DontSync, "\uF195" },
{ WinoIconGlyph.Move, "\uE7B8" },
{ WinoIconGlyph.Mail, "\uF509" },
{ WinoIconGlyph.More, "\uE824" },
{ WinoIconGlyph.CustomServer, "\uF509" },
};
}
}

View File

@@ -1,155 +0,0 @@
using System;
using System.Text.RegularExpressions;
using Fernandezja.ColorHashSharp;
using Windows.UI;
using Wino.Core.Services;
#if NET8_0
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using Microsoft.UI.Xaml.Shapes;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Shapes;
#endif
namespace Wino.Controls
{
public 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 IsKnownProperty = DependencyProperty.Register(nameof(IsKnown), typeof(bool), typeof(ImagePreviewControl), new PropertyMetadata(false));
public string FromName
{
get { return (string)GetValue(FromNameProperty); }
set { SetValue(FromNameProperty, value); }
}
public string FromAddress
{
get { return (string)GetValue(FromAddressProperty); }
set { SetValue(FromAddressProperty, value); }
}
public bool IsKnown
{
get { return (bool)GetValue(IsKnownProperty); }
set { SetValue(IsKnownProperty, value); }
}
#endregion
private Ellipse Ellipse;
private Grid InitialsGrid;
private TextBlock InitialsTextblock;
private Image KnownHostImage;
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 void UpdateInformation()
{
if (KnownHostImage == null || InitialsGrid == null || InitialsTextblock == null || (string.IsNullOrEmpty(FromName) && string.IsNullOrEmpty(FromAddress)))
return;
var host = ThumbnailService.GetHost(FromAddress);
if (!string.IsNullOrEmpty(host))
{
var tuple = ThumbnailService.CheckIsKnown(host);
IsKnown = tuple.Item1;
host = tuple.Item2;
}
if (IsKnown)
{
// Unrealize others.
KnownHostImage.Visibility = Visibility.Visible;
InitialsGrid.Visibility = Visibility.Collapsed;
// Apply company logo.
KnownHostImage.Source = new BitmapImage(new Uri(ThumbnailService.GetKnownHostImage(host)));
}
else
{
KnownHostImage.Visibility = Visibility.Collapsed;
InitialsGrid.Visibility = Visibility.Visible;
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);
}
}
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();
}
}
}

View File

@@ -1,276 +0,0 @@
<UserControl
x:Class="Wino.Controls.MailItemDisplayInformationControl"
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:helpers="using:Wino.Helpers"
PointerEntered="ControlPointerEntered"
PointerExited="ControlPointerExited">
<UserControl.Resources>
<Style
x:Key="HoverActionButtonStyle"
BasedOn="{StaticResource DefaultButtonStyle}"
TargetType="Button">
<Setter Property="Padding" Value="0" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
</Style>
</UserControl.Resources>
<Grid Background="Transparent" Tapped="ThreadHeaderTapped">
<Grid.RowDefinitions>
<RowDefinition x:Name="ContainerHeight" Height="Auto" />
</Grid.RowDefinitions>
<Grid
x:Name="RootContainer"
Padding="0,1"
x:DefaultBindMode="OneWay">
<!-- Custom Interaction Focus Indicator -->
<Ellipse
Width="8"
Height="8"
Canvas.ZIndex="9999"
Margin="0,12,8,0"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Visibility="{x:Bind IsCustomFocused, Mode=OneWay}"
Fill="{ThemeResource SystemAccentColor}" />
<Border
x:Name="RootContainerVisualWrapper"
Margin="0,4"
Background="Transparent"
BorderBrush="Transparent"
BorderThickness="0.5"
CornerRadius="4" />
<Grid x:Name="MainContentContainer">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<controls:ImagePreviewControl
x:Name="ContactImage"
Width="35"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="14"
FromAddress="{x:Bind FromAddress, Mode=OneWay}"
FromName="{x:Bind DisplayName, Mode=OneWay}"
Visibility="{x:Bind IsAvatarVisible, Mode=OneWay}" />
<Grid
x:Name="ContentGrid"
Grid.Column="1"
Canvas.ZIndex="2">
<!-- Sender + Title -->
<Grid x:Name="ContentStackpanel" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Sender + IsDraft + Hover Buttons -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- IsDraft Tag -->
<TextBlock
x:Name="DraftTitle"
Margin="0,0,4,0"
x:Load="{x:Bind IsDraft, Mode=OneWay}"
Foreground="{StaticResource DeleteBrush}">
<Run Text="[" /><Run Text="{x:Bind domain:Translator.Draft}" /><Run Text="]" /> <Run Text=" " />
</TextBlock>
<!-- Sender -->
<TextBlock
x:Name="SenderText"
Grid.Column="1"
Text="{x:Bind DisplayName}"
TextTrimming="WordEllipsis" />
<!-- Hover button -->
<StackPanel
x:Name="HoverActionButtons"
Grid.Column="2"
HorizontalAlignment="Right"
Background="Transparent"
Canvas.ZIndex="10"
Orientation="Horizontal"
Spacing="12"
Visibility="Collapsed">
<StackPanel.ChildrenTransitions>
<TransitionCollection>
<EdgeUIThemeTransition Edge="Right" />
</TransitionCollection>
</StackPanel.ChildrenTransitions>
<Button Click="FirstActionClicked" Style="{StaticResource HoverActionButtonStyle}">
<Button.Content>
<controls:WinoFontIcon FontSize="16" Icon="{x:Bind helpers:XamlHelpers.GetWinoIconGlyph(LeftHoverAction), Mode=OneWay}" />
</Button.Content>
</Button>
<Button Click="SecondActionClicked" Style="{StaticResource HoverActionButtonStyle}">
<Button.Content>
<controls:WinoFontIcon FontSize="16" Icon="{x:Bind helpers:XamlHelpers.GetWinoIconGlyph(CenterHoverAction), Mode=OneWay}" />
</Button.Content>
</Button>
<Button Click="ThirdActionClicked" Style="{StaticResource HoverActionButtonStyle}">
<Button.Content>
<controls:WinoFontIcon FontSize="16" Icon="{x:Bind helpers:XamlHelpers.GetWinoIconGlyph(RightHoverAction), Mode=OneWay}" />
</Button.Content>
</Button>
</StackPanel>
</Grid>
<!-- Subject + IsDraft -->
<Grid Grid.Row="1" ColumnSpacing="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock
x:Name="TitleText"
MaxLines="1"
Text="{x:Bind Subject}"
TextTrimming="CharacterEllipsis" />
<TextBlock
Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontSize="11"
Opacity="0.7"
Text="{x:Bind helpers:XamlHelpers.GetMailItemDisplaySummaryForListing(IsDraft, ReceivedDate, Prefer24HourTimeFormat)}" />
</Grid>
<!-- Message -->
<Grid
x:Name="PreviewTextContainerRoot"
Grid.Row="2"
VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid x:Name="PreviewTextContainer">
<TextBlock
x:Name="PreviewTextblock"
x:Load="{x:Bind helpers:XamlHelpers.ShouldDisplayPreview(Snippet), Mode=OneWay}"
MaxLines="1"
Opacity="0.7"
Text="{x:Bind Snippet}"
TextTrimming="CharacterEllipsis" />
</Grid>
<!-- Right Icons Container -->
<StackPanel
x:Name="IconsContainer"
Grid.Column="1"
Margin="4,4,1,4"
Orientation="Horizontal"
Spacing="2">
<ContentPresenter
x:Name="HasAttachmentContent"
x:Load="{x:Bind HasAttachments, Mode=OneWay}"
ContentTemplate="{StaticResource AttachmentSymbolControlTemplate}" />
<ContentPresenter
x:Name="IsFlaggedContent"
x:Load="{x:Bind IsFlagged, Mode=OneWay}"
ContentTemplate="{StaticResource FlaggedSymbolControlTemplate}" />
</StackPanel>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
<VisualStateManager.VisualStateGroups>
<!-- Read States -->
<VisualStateGroup x:Name="ReadStates">
<VisualState x:Name="Unread">
<VisualState.StateTriggers>
<StateTrigger IsActive="{x:Bind IsRead, Converter={StaticResource ReverseBooleanConverter}, Mode=OneWay}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="TitleText.Foreground" Value="{ThemeResource SystemAccentColor}" />
<Setter Target="TitleText.FontWeight" Value="Semibold" />
<Setter Target="SenderText.FontWeight" Value="Semibold" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Read" />
</VisualStateGroup>
<!-- Sizing States -->
<VisualStateGroup x:Name="SizingStates">
<VisualState x:Name="Compact">
<VisualState.Setters>
<Setter Target="ContainerHeight.Height" Value="50" />
<Setter Target="ContentGrid.Padding" Value="8,0" />
<Setter Target="PreviewTextContainer.Visibility" Value="Collapsed" />
</VisualState.Setters>
<VisualState.StateTriggers>
<StateTrigger IsActive="{x:Bind helpers:XamlHelpers.ObjectEquals(DisplayMode, enums:MailListDisplayMode.Compact), Mode=OneWay}" />
</VisualState.StateTriggers>
</VisualState>
<!-- Medium -->
<VisualState x:Name="Medium">
<VisualState.Setters>
<Setter Target="ContainerHeight.Height" Value="65" />
<Setter Target="ContentGrid.Padding" Value="6,0" />
<Setter Target="PreviewTextContainer.Visibility" Value="Visible" />
</VisualState.Setters>
<VisualState.StateTriggers>
<StateTrigger IsActive="{x:Bind helpers:XamlHelpers.ObjectEquals(DisplayMode, enums:MailListDisplayMode.Medium), Mode=OneWay}" />
</VisualState.StateTriggers>
</VisualState>
<!-- Spacious -->
<VisualState x:Name="Spacious">
<VisualState.Setters>
<Setter Target="ContainerHeight.Height" Value="Auto" />
<Setter Target="ContentGrid.Padding" Value="12,12,6,12" />
<Setter Target="PreviewTextContainer.Visibility" Value="Visible" />
</VisualState.Setters>
<VisualState.StateTriggers>
<StateTrigger IsActive="{x:Bind helpers:XamlHelpers.ObjectEquals(DisplayMode, enums:MailListDisplayMode.Spacious), Mode=OneWay}" />
</VisualState.StateTriggers>
</VisualState>
</VisualStateGroup>
<!-- Preview Text States -->
<VisualStateGroup x:Name="PreviewTextStates">
<VisualState x:Name="ShowText" />
<VisualState x:Name="HideText">
<VisualState.Setters>
<Setter Target="PreviewTextContainerRoot.Visibility" Value="Collapsed" />
</VisualState.Setters>
<VisualState.StateTriggers>
<StateTrigger IsActive="{x:Bind ShowPreviewText, Mode=OneWay, Converter={StaticResource ReverseBooleanConverter}}" />
</VisualState.StateTriggers>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</UserControl>

View File

@@ -1,287 +0,0 @@
using System;
using System.ComponentModel;
using System.Numerics;
using System.Windows.Input;
using Microsoft.UI.Xaml.Controls;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Models.MailItem;
using Wino.Extensions;
using Wino.Mail.ViewModels.Data;
#if NET8_0
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Input;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
#endif
namespace Wino.Controls
{
public sealed partial class MailItemDisplayInformationControl : UserControl, INotifyPropertyChanged
{
public ImagePreviewControl GetImagePreviewControl() => ContactImage;
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 SnippetProperty = DependencyProperty.Register(nameof(Snippet), typeof(string), typeof(MailItemDisplayInformationControl), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty FromNameProperty = DependencyProperty.Register(nameof(FromName), typeof(string), typeof(MailItemDisplayInformationControl), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty SubjectProperty = DependencyProperty.Register(nameof(Subject), typeof(string), typeof(MailItemDisplayInformationControl), new PropertyMetadata("(no-subject)"));
public static readonly DependencyProperty IsReadProperty = DependencyProperty.Register(nameof(IsRead), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false));
public static readonly DependencyProperty IsFlaggedProperty = DependencyProperty.Register(nameof(IsFlagged), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false));
public static readonly DependencyProperty FromAddressProperty = DependencyProperty.Register(nameof(FromAddress), typeof(string), typeof(MailItemDisplayInformationControl), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty HasAttachmentsProperty = DependencyProperty.Register(nameof(HasAttachments), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false));
public static readonly DependencyProperty IsCustomFocusedProperty = DependencyProperty.Register(nameof(IsCustomFocused), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false));
public static readonly DependencyProperty ReceivedDateProperty = DependencyProperty.Register(nameof(ReceivedDate), typeof(DateTime), typeof(MailItemDisplayInformationControl), new PropertyMetadata(default(DateTime)));
public static readonly DependencyProperty IsDraftProperty = DependencyProperty.Register(nameof(IsDraft), 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 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));
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 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 event PropertyChangedEventHandler PropertyChanged;
public Expander ConnectedExpander
{
get { return (Expander)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 IsDraft
{
get { return (bool)GetValue(IsDraftProperty); }
set { SetValue(IsDraftProperty, value); }
}
public DateTime ReceivedDate
{
get { return (DateTime)GetValue(ReceivedDateProperty); }
set { SetValue(ReceivedDateProperty, value); }
}
public bool IsCustomFocused
{
get { return (bool)GetValue(IsCustomFocusedProperty); }
set { SetValue(IsCustomFocusedProperty, value); }
}
public bool HasAttachments
{
get { return (bool)GetValue(HasAttachmentsProperty); }
set { SetValue(HasAttachmentsProperty, value); }
}
public bool IsRead
{
get { return (bool)GetValue(IsReadProperty); }
set { SetValue(IsReadProperty, value); }
}
public bool IsFlagged
{
get { return (bool)GetValue(IsFlaggedProperty); }
set { SetValue(IsFlaggedProperty, value); }
}
public string FromAddress
{
get { return (string)GetValue(FromAddressProperty); }
set
{
SetValue(FromAddressProperty, value);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(DisplayName)));
}
}
public string DisplayName
{
get
{
if (string.IsNullOrEmpty(FromName))
return FromAddress;
return FromName;
}
}
public string FromName
{
get => (string)GetValue(FromNameProperty);
set
{
SetValue(FromNameProperty, value);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(DisplayName)));
}
}
public string Subject
{
get { return (string)GetValue(SubjectProperty); }
set { SetValue(SubjectProperty, value); }
}
public string Snippet
{
get { return (string)GetValue(SnippetProperty); }
set { SetValue(SnippetProperty, 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); }
}
private bool tappedHandlingFlag = false;
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 void ControlPointerEntered(object sender, PointerRoutedEventArgs e)
{
if (IsHoverActionsEnabled)
{
HoverActionButtons.Visibility = Visibility.Visible;
}
}
private void ControlPointerExited(object sender, PointerRoutedEventArgs e)
{
if (IsHoverActionsEnabled)
{
HoverActionButtons.Visibility = Visibility.Collapsed;
}
}
private void ExecuteHoverAction(MailOperation operation)
{
MailOperationPreperationRequest package = null;
if (MailItem is MailItemViewModel mailItemViewModel)
package = new MailOperationPreperationRequest(operation, mailItemViewModel.MailCopy, toggleExecution: true);
else if (MailItem is ThreadMailItemViewModel threadMailItemViewModel)
package = new MailOperationPreperationRequest(operation, threadMailItemViewModel.GetMailCopies(), toggleExecution: true);
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);
}
private void SecondActionClicked(object sender, RoutedEventArgs e)
{
ExecuteHoverAction(CenterHoverAction);
}
private void ThirdActionClicked(object sender, RoutedEventArgs e)
{
ExecuteHoverAction(RightHoverAction);
}
}
}

View File

@@ -1,141 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Input;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Models.Menus;
using Wino.Helpers;
using Wino.MenuFlyouts;
#if NET8_0
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
#endif
namespace Wino.Controls
{
public class RendererCommandBar : CommandBar, IDisposable
{
public static readonly DependencyProperty MenuItemsProperty = DependencyProperty.Register(nameof(MenuItemsProperty), typeof(ObservableCollection<MailOperationMenuItem>), typeof(RendererCommandBar), new PropertyMetadata(null, OnMenuItemsChanged));
public static readonly DependencyProperty OperationClickedCommandProperty = DependencyProperty.Register(nameof(OperationClickedCommand), typeof(ICommand), typeof(RendererCommandBar), new PropertyMetadata(null));
public ICommand OperationClickedCommand
{
get { return (ICommand)GetValue(OperationClickedCommandProperty); }
set { SetValue(OperationClickedCommandProperty, value); }
}
public ObservableCollection<MailOperationMenuItem> MenuItems
{
get { return (ObservableCollection<MailOperationMenuItem>)GetValue(MenuItemsProperty); }
set { SetValue(MenuItemsProperty, value); }
}
public RendererCommandBar()
{
this.DefaultStyleKey = typeof(CommandBar);
}
private static void OnMenuItemsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is RendererCommandBar commandBar)
{
if (args.OldValue != null)
commandBar.UnregisterButtonCollection(args.NewValue as ObservableCollection<MailOperationMenuItem>);
if (args.NewValue != null)
commandBar.RegisterButtonCollection(args.NewValue as ObservableCollection<MailOperationMenuItem>);
}
}
private void RegisterButtonCollection(ObservableCollection<MailOperationMenuItem> collection)
{
collection.CollectionChanged -= ButtonCollectionChanged;
collection.CollectionChanged += ButtonCollectionChanged;
InitItems(collection);
}
private void UnregisterButtonCollection(ObservableCollection<MailOperationMenuItem> collection)
{
collection.CollectionChanged -= ButtonCollectionChanged;
}
// One time initializer on registration.
private void InitItems(IEnumerable<MailOperationMenuItem> items)
{
foreach (var item in items)
{
var operationText = XamlHelpers.GetOperationString(item.Operation);
var operationAppBarItem = new AppBarButton()
{
Label = operationText
};
ToolTipService.SetToolTip(operationAppBarItem, operationText);
PrimaryCommands.Add(operationAppBarItem);
}
}
private void ButtonCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Reset)
{
PrimaryCommands.Clear();
SecondaryCommands.Clear();
}
if (e.NewItems != null)
{
foreach (var newItem in e.NewItems)
{
if (newItem is MailOperationMenuItem item)
{
var button = new RendererCommandBarItem(item.Operation, Clicked)
{
IsEnabled = item.IsEnabled
};
if (!item.IsSecondaryMenuPreferred)
PrimaryCommands.Add(button);
else
SecondaryCommands.Add(button);
}
}
}
}
private void Clicked(MailOperation operation)
{
OperationClickedCommand?.Execute(operation);
}
private void DisposeMenuItems()
{
foreach (var item in this.PrimaryCommands)
{
if (item is RendererCommandBarItem rendererCommandBarItem)
{
rendererCommandBarItem.Dispose();
}
}
foreach (var item in this.SecondaryCommands)
{
if (item is RendererCommandBarItem rendererCommandBarItem)
{
rendererCommandBarItem.Dispose();
}
}
}
public void Dispose()
{
DisposeMenuItems();
}
}
}

View File

@@ -1,77 +0,0 @@
using System.Windows.Input;
#if NET8_0
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
#endif
namespace Wino.Controls
{
/// <summary>
/// Templated button for each setting in Settings Dialog.
/// </summary>
public class SettingsMenuItemControl : Control
{
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));
}
}

View File

@@ -1,104 +0,0 @@
#if NET8_0
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
#else
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
#endif
namespace Wino.Controls
{
public enum WinoIconGlyph
{
None,
NewMail,
Google,
Microsoft,
CustomServer,
Archive,
UnArchive,
Reply,
ReplyAll,
LightEditor,
DarkEditor,
Delete,
Move,
Mail,
Draft,
Flag,
ClearFlag,
Folder,
Forward,
Inbox,
MarkRead,
MarkUnread,
Send,
Save,
Sync,
MultiSelect,
Zoom,
Pin,
UnPin,
Ignore,
Star,
CreateFolder,
Junk,
More,
Find,
SpecialFolderInbox,
SpecialFolderStarred,
SpecialFolderImportant,
SpecialFolderSent,
SpecialFolderDraft,
SpecialFolderArchive,
SpecialFolderDeleted,
SpecialFolderJunk,
SpecialFolderChat,
SpecialFolderCategory,
SpecialFolderUnread,
SpecialFolderForums,
SpecialFolderUpdated,
SpecialFolderPersonal,
SpecialFolderPromotions,
SpecialFolderSocial,
SpecialFolderOther,
SpecialFolderMore,
TurnOfNotifications,
EmptyFolder,
Rename,
DontSync
}
public class WinoFontIcon : FontIcon
{
public WinoIconGlyph Icon
{
get { return (WinoIconGlyph)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public static readonly DependencyProperty IconProperty = DependencyProperty.Register(nameof(Icon), typeof(WinoIconGlyph), typeof(WinoFontIcon), new PropertyMetadata(WinoIconGlyph.Flag, OnIconChanged));
public WinoFontIcon()
{
FontFamily = new FontFamily("ms-appx:///Assets/WinoIcons.ttf#WinoIcons");
FontSize = 32;
}
private static void OnIconChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is WinoFontIcon fontIcon)
{
fontIcon.UpdateGlyph();
}
}
private void UpdateGlyph()
{
Glyph = ControlConstants.WinoIconFontDictionary[Icon];
}
}
}

View File

@@ -1,41 +0,0 @@
#if NET8_0
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
#endif
namespace Wino.Controls
{
public class WinoFontIconSource : Microsoft.UI.Xaml.Controls.FontIconSource
{
public WinoIconGlyph Icon
{
get { return (WinoIconGlyph)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public static readonly DependencyProperty IconProperty = DependencyProperty.Register(nameof(Icon), typeof(WinoIconGlyph), typeof(WinoFontIconSource), new PropertyMetadata(WinoIconGlyph.Flag, OnIconChanged));
public WinoFontIconSource()
{
FontFamily = new FontFamily("ms-appx:///Assets/WinoIcons.ttf#WinoIcons");
FontSize = 32;
}
private static void OnIconChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is WinoFontIconSource fontIcon)
{
fontIcon.UpdateGlyph();
}
}
private void UpdateGlyph()
{
Glyph = ControlConstants.WinoIconFontDictionary[Icon];
}
}
}

View File

@@ -1,97 +0,0 @@
using System;
using System.Numerics;
using Microsoft.UI.Xaml.Controls;
using Wino.Core.Domain.Enums;
using CommunityToolkit.WinUI.Animations;
#if NET8_0
using Microsoft.UI.Xaml;
#else
using Windows.UI.Xaml;
#endif
namespace Wino.Controls
{
public class WinoInfoBar : InfoBar
{
public static readonly DependencyProperty AnimationTypeProperty = DependencyProperty.Register(nameof(AnimationType), typeof(InfoBarAnimationType), typeof(WinoInfoBar), new PropertyMetadata(InfoBarAnimationType.SlideFromRightToLeft));
public static readonly DependencyProperty DismissIntervalProperty = DependencyProperty.Register(nameof(DismissInterval), typeof(int), typeof(WinoInfoBar), new PropertyMetadata(5, new PropertyChangedCallback(OnDismissIntervalChanged)));
public InfoBarAnimationType AnimationType
{
get { return (InfoBarAnimationType)GetValue(AnimationTypeProperty); }
set { SetValue(AnimationTypeProperty, value); }
}
public int DismissInterval
{
get { return (int)GetValue(DismissIntervalProperty); }
set { SetValue(DismissIntervalProperty, value); }
}
private readonly DispatcherTimer _dispatcherTimer = new DispatcherTimer();
public WinoInfoBar()
{
RegisterPropertyChangedCallback(IsOpenProperty, IsOpenChanged);
_dispatcherTimer.Interval = TimeSpan.FromSeconds(DismissInterval);
}
private static void OnDismissIntervalChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is WinoInfoBar bar)
{
bar.UpdateInterval(bar.DismissInterval);
}
}
private void UpdateInterval(int seconds) => _dispatcherTimer.Interval = TimeSpan.FromSeconds(seconds);
private async void IsOpenChanged(DependencyObject sender, DependencyProperty dp)
{
if (sender is WinoInfoBar control)
{
// Message shown.
if (!control.IsOpen) return;
Opacity = 1;
_dispatcherTimer.Stop();
_dispatcherTimer.Tick -= TimerTick;
_dispatcherTimer.Tick += TimerTick;
_dispatcherTimer.Start();
// Slide from right.
if (AnimationType == InfoBarAnimationType.SlideFromRightToLeft)
{
await AnimationBuilder.Create().Translation(new Vector3(0, 0, 0), new Vector3(150, 0, 0), null, TimeSpan.FromSeconds(0.5)).StartAsync(this);
}
else if (AnimationType == InfoBarAnimationType.SlideFromBottomToTop)
{
await AnimationBuilder.Create().Translation(new Vector3(0, 0, 0), new Vector3(0, 50, 0), null, TimeSpan.FromSeconds(0.5)).StartAsync(this);
}
}
}
private async void TimerTick(object sender, object e)
{
_dispatcherTimer.Stop();
_dispatcherTimer.Tick -= TimerTick;
if (AnimationType == InfoBarAnimationType.SlideFromRightToLeft)
{
await AnimationBuilder.Create().Translation(new Vector3((float)ActualWidth, 0, 0), new Vector3(0, 0, 0), null, TimeSpan.FromSeconds(0.5)).StartAsync(this);
}
else if (AnimationType == InfoBarAnimationType.SlideFromBottomToTop)
{
await AnimationBuilder.Create().Translation(new Vector3(0, (float)ActualHeight, 0), new Vector3(0, 0, 0), null, TimeSpan.FromSeconds(0.5)).StartAsync(this);
}
IsOpen = false;
}
}
}

View File

@@ -1,52 +0,0 @@
using System.Numerics;
using Microsoft.UI.Xaml.Controls;
#if NET8_0
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Hosting;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Hosting;
#endif
namespace Wino.Controls
{
public class WinoNavigationViewItem : NavigationViewItem
{
public bool IsDraggingItemOver
{
get { return (bool)GetValue(IsDraggingItemOverProperty); }
set { SetValue(IsDraggingItemOverProperty, value); }
}
public static readonly DependencyProperty IsDraggingItemOverProperty = DependencyProperty.Register(nameof(IsDraggingItemOver), typeof(bool), typeof(WinoNavigationViewItem), new PropertyMetadata(false, OnIsDraggingItemOverChanged));
private static void OnIsDraggingItemOverChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is WinoNavigationViewItem control)
control.UpdateDragEnterState();
}
private void UpdateDragEnterState()
{
// TODO: Add animation. Maybe after overriding DragUI in shell?
//if (IsDraggingItemOver)
//{
// ScaleAnimation(new System.Numerics.Vector3(1.2f, 1.2f, 1.2f));
//}
//else
//{
// ScaleAnimation(new System.Numerics.Vector3(1f, 1f, 1f));
//}
}
private void ScaleAnimation(Vector3 vector)
{
if (this.Content is UIElement content)
{
var visual = ElementCompositionPreview.GetElementVisual(content);
visual.Scale = vector;
}
}
}
}

View File

@@ -1,123 +0,0 @@
<UserControl
x:Class="Wino.Controls.WinoPivotControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="400"
Loaded="ControlLoaded"
Unloaded="ControlUnloaded"
mc:Ignorable="d">
<UserControl.Resources>
<Style x:Key="WinoPivotControlListViewItemStyle" TargetType="ListViewItem">
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="Background" Value="{ThemeResource ListViewItemBackground}" />
<Setter Property="Foreground" Value="{ThemeResource ListViewItemForeground}" />
<Setter Property="TabNavigation" Value="Local" />
<Setter Property="IsHoldingEnabled" Value="True" />
<Setter Property="Padding" Value="12,4" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="MinWidth" Value="{ThemeResource ListViewItemMinWidth}" />
<Setter Property="MinHeight" Value="{ThemeResource ListViewItemMinHeight}" />
<Setter Property="AllowDrop" Value="False" />
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="FocusVisualMargin" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ListViewItemPresenter
x:Name="Root"
Margin="0,0,6,0"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
CheckBoxBrush="{ThemeResource ListViewItemCheckBoxBrush}"
CheckBrush="{ThemeResource ListViewItemCheckBrush}"
CheckMode="{ThemeResource ListViewItemCheckMode}"
ContentMargin="{TemplateBinding Padding}"
ContentTransitions="{TemplateBinding ContentTransitions}"
Control.IsTemplateFocusTarget="True"
CornerRadius="6"
DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}"
DragBackground="{ThemeResource ListViewItemDragBackground}"
DragForeground="{ThemeResource ListViewItemDragForeground}"
DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}"
FocusBorderBrush="{ThemeResource ListViewItemFocusBorderBrush}"
FocusSecondaryBorderBrush="{ThemeResource ListViewItemFocusSecondaryBorderBrush}"
FocusVisualMargin="{TemplateBinding FocusVisualMargin}"
PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackground}"
PointerOverBackground="{ThemeResource ListViewItemBackgroundPointerOver}"
PointerOverForeground="{ThemeResource ListViewItemForegroundPointerOver}"
PressedBackground="Transparent"
ReorderHintOffset="{ThemeResource ListViewItemReorderHintThemeOffset}"
RevealBackground="Transparent"
RevealBorderBrush="Transparent"
RevealBorderThickness="{ThemeResource ListViewItemRevealBorderThemeThickness}"
SelectedBackground="Transparent"
SelectedForeground="{ThemeResource ApplicationForegroundThemeBrush}"
SelectedPointerOverBackground="{ThemeResource ListViewItemBackgroundPointerOver}"
SelectedPressedBackground="{ThemeResource ListViewItemBackgroundPointerOver}"
SelectionCheckMarkVisualEnabled="{ThemeResource ListViewItemSelectionCheckMarkVisualEnabled}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected" />
<VisualState x:Name="PointerOver" />
<VisualState x:Name="PointerOverSelected" />
<VisualState x:Name="PointerOverPressed" />
<VisualState x:Name="Pressed" />
<VisualState x:Name="PressedSelected" />
</VisualStateGroup>
<VisualStateGroup x:Name="DisabledStates">
<VisualState x:Name="Enabled" />
<VisualState x:Name="Disabled" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ListViewItemPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListView
x:Name="PivotHeaders"
ItemContainerStyle="{StaticResource WinoPivotControlListViewItemStyle}"
ItemTemplate="{x:Bind DataTemplate, Mode=OneWay}"
ItemsSource="{x:Bind ItemsSource, Mode=OneWay}"
Transitions="{x:Null}"
ItemContainerTransitions="{x:Null}"
SelectedItem="{x:Bind SelectedItem, Mode=TwoWay}"
SelectionChanged="PivotHeaders_SelectionChanged">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
<Grid
x:Name="SelectorPipe"
Grid.Row="1"
Width="1"
Height="3"
Margin="0,6,0,0"
HorizontalAlignment="Left"
SizeChanged="SelectorPipeSizeChanged">
<Grid.TranslationTransition>
<Vector3Transition Duration="0:0:0.5" />
</Grid.TranslationTransition>
</Grid>
</Grid>
</UserControl>

View File

@@ -1,198 +0,0 @@
using System;
using System.Diagnostics;
using System.Numerics;
using System.Threading.Tasks;
using Windows.Foundation;
using Wino.Extensions;
#if NET8_0
using Microsoft.UI;
using Microsoft.UI.Composition;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
#else
using Windows.UI;
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
#endif
namespace Wino.Controls
{
// TODO: Memory leak with FolderPivot bindings.
public sealed partial class WinoPivotControl : UserControl
{
private Compositor _compositor;
private ShapeVisual _shapeVisual;
private CompositionSpriteShape _spriteShape;
private CompositionRoundedRectangleGeometry _roundedRectangle;
public event EventHandler<SelectionChangedEventArgs> SelectionChanged;
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(nameof(SelectedItem), typeof(object), typeof(WinoPivotControl), new PropertyMetadata(null));
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(nameof(ItemsSource), typeof(object), typeof(WinoPivotControl), new PropertyMetadata(null));
public static readonly DependencyProperty SelectorPipeColorProperty = DependencyProperty.Register(nameof(SelectorPipeColor), typeof(SolidColorBrush), typeof(WinoPivotControl), new PropertyMetadata(Colors.Transparent, OnSelectorPipeColorChanged));
public static readonly DependencyProperty DataTemplateProperty = DependencyProperty.Register(nameof(DataTemplate), typeof(DataTemplate), typeof(WinoPivotControl), new PropertyMetadata(null));
public DataTemplate DataTemplate
{
get { return (DataTemplate)GetValue(DataTemplateProperty); }
set { SetValue(DataTemplateProperty, value); }
}
public SolidColorBrush SelectorPipeColor
{
get { return (SolidColorBrush)GetValue(SelectorPipeColorProperty); }
set { SetValue(SelectorPipeColorProperty, value); }
}
public object SelectedItem
{
get { return (object)GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
public object ItemsSource
{
get { return (object)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
private static void OnSelectorPipeColorChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is WinoPivotControl control)
{
control.UpdateSelectorPipeColor();
}
}
private void UpdateSelectorPipeColor()
{
if (_spriteShape != null && _compositor != null)
{
_spriteShape.FillBrush = _compositor.CreateColorBrush(SelectorPipeColor.Color);
}
}
private void CreateSelectorVisuals()
{
_compositor = this.Visual().Compositor;
_roundedRectangle = _compositor.CreateRoundedRectangleGeometry();
_roundedRectangle.CornerRadius = new Vector2(3, 3);
_spriteShape = _compositor.CreateSpriteShape(_roundedRectangle);
_spriteShape.CenterPoint = new Vector2(100, 100);
_shapeVisual = _compositor.CreateShapeVisual();
_shapeVisual.Shapes.Clear();
_shapeVisual.Shapes.Add(_spriteShape);
SelectorPipe.SetChildVisual(_shapeVisual);
_shapeVisual.EnableImplicitAnimation(VisualPropertyType.Size, 400);
}
public WinoPivotControl()
{
this.InitializeComponent();
CreateSelectorVisuals();
}
private bool IsContainerPresent()
{
return SelectedItem != null && PivotHeaders.ContainerFromItem(SelectedItem) != null;
}
private void PivotHeaders_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
UpdateVisuals();
SelectionChanged?.Invoke(sender, e);
}
private void UpdateVisuals()
{
MoveSelector();
}
private void UpdateSelectorVisibility()
{
SelectorPipe.Visibility = IsContainerPresent() ? Visibility.Visible : Visibility.Collapsed;
}
private async void MoveSelector()
{
if (PivotHeaders.SelectedItem != null)
{
// Get selected item container position
// TODO: It's bad...
while (PivotHeaders.ContainerFromItem(PivotHeaders.SelectedItem) == null)
{
await Task.Delay(100);
}
UpdateSelectorVisibility();
var container = PivotHeaders.ContainerFromItem(PivotHeaders.SelectedItem) as FrameworkElement;
if (container != null)
{
var transformToVisual = container.TransformToVisual(this);
Point screenCoords = transformToVisual.TransformPoint(new Point(0, 0));
float actualWidth = 0, leftMargin = 0, translateX = 0;
leftMargin = (float)(screenCoords.X);
if (PivotHeaders.Items.Count > 1)
{
// Multiple items, pipe is centered.
actualWidth = (float)(container.ActualWidth + 12) / 2;
translateX = leftMargin - 10 + (actualWidth / 2);
}
else
{
actualWidth = (float)(container.ActualWidth) - 12;
translateX = leftMargin + 4;
}
SelectorPipe.Width = actualWidth;
SelectorPipe.Translation = new Vector3(translateX, 0, 0);
}
else
{
Debug.WriteLine("Container null");
}
}
}
private void SelectorPipeSizeChanged(object sender, SizeChangedEventArgs e)
{
_roundedRectangle.Size = e.NewSize.ToVector2();
_shapeVisual.Size = e.NewSize.ToVector2();
}
private void ControlUnloaded(object sender, RoutedEventArgs e)
{
//PivotHeaders.SelectionChanged -= PivotHeaders_SelectionChanged;
//PivotHeaders.SelectedItem = null;
//SelectedItem = null;
//ItemsSource = null;
}
private void ControlLoaded(object sender, RoutedEventArgs e)
{
// Bindings.Update();
}
}
}

View File

@@ -1,87 +0,0 @@
using System.Linq;
using Microsoft.UI.Xaml.Controls;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Models.MailItem;
using Wino.Helpers;
using Wino.Mail.ViewModels.Data;
#if NET8_0
using Microsoft.UI.Xaml;
#else
using Windows.UI.Xaml;
#endif
namespace Wino.Controls
{
public 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
{
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;
}
}
}