Merge pull request #344 from bkaankose/features/action-bar

Mail List action bar improvements
This commit is contained in:
Burak Kaan Köse
2024-08-31 15:28:59 +02:00
committed by GitHub
16 changed files with 224 additions and 633 deletions

View File

@@ -155,5 +155,10 @@ namespace Wino.Core.Domain.Interfaces
/// Setting: Gets or sets what should happen to server app when the client is terminated.
/// </summary>
ServerBackgroundMode ServerTerminationBehavior { get; set; }
/// <summary>
/// Setting: Whether the mail list action bar is enabled or not.
/// </summary>
bool IsMailListActionBarEnabled { get; set; }
}
}

View File

@@ -519,7 +519,7 @@
"SettingsRenameMergeAccount_Title": "Rename",
"SettingsSemanticZoom_Description": "This will allow you to click on the headers in messages list and go to specific date",
"SettingsSemanticZoom_Title": "Semantic Zoom for Date Headers",
"SettingsShowPreviewText_Description": "Hide/show thepreview text.",
"SettingsShowPreviewText_Description": "Hide/show the preview text.",
"SettingsShowPreviewText_Title": "Show Preview Text",
"SettingsShowSenderPictures_Description": "Hide/show the thumbnail sender pictures.",
"SettingsShowSenderPictures_Title": "Show Sender Avatars",
@@ -533,7 +533,9 @@
"SettingsStore_Title": "Rate in Store",
"SettingsThreads_Description": "Organize messages into conversation threads.",
"SettingsThreads_Title": "Conversation Threading",
"SettingsUnlinkAccounts_Description": "Remove the link between accounts. This will not delete your accounts.",
"SettingsMailListActionBar_Description": "Hide/show action bar at top of message list.",
"SettingsMailListActionBar_Title": "Show mail list actions",
"SettingsUnlinkAccounts_Description": "Remove the link between accounts. his will not delete your accounts.",
"SettingsUnlinkAccounts_Title": "Unlink Accounts",
"SortingOption_Date": "by date",
"SortingOption_Name": "by name",

View File

@@ -2619,7 +2619,7 @@ namespace Wino.Core.Domain
public static string SettingsSemanticZoom_Title => Resources.GetTranslatedString(@"SettingsSemanticZoom_Title");
/// <summary>
/// Hide/show thepreview text.
/// Hide/show the preview text.
/// </summary>
public static string SettingsShowPreviewText_Description => Resources.GetTranslatedString(@"SettingsShowPreviewText_Description");
@@ -2689,7 +2689,17 @@ namespace Wino.Core.Domain
public static string SettingsThreads_Title => Resources.GetTranslatedString(@"SettingsThreads_Title");
/// <summary>
/// Remove the link between accounts. This will not delete your accounts.
/// Hide/show action bar at top of message list.
/// </summary>
public static string SettingsMailListActionBar_Description => Resources.GetTranslatedString(@"SettingsMailListActionBar_Description");
/// <summary>
/// Show mail list actions
/// </summary>
public static string SettingsMailListActionBar_Title => Resources.GetTranslatedString(@"SettingsMailListActionBar_Title");
/// <summary>
/// Remove the link between accounts. his will not delete your accounts.
/// </summary>
public static string SettingsUnlinkAccounts_Description => Resources.GetTranslatedString(@"SettingsUnlinkAccounts_Description");

View File

@@ -64,6 +64,12 @@ namespace Wino.Core.UWP.Services
set => SetPropertyAndSave(nameof(IsThreadingEnabled), value);
}
public bool IsMailListActionBarEnabled
{
get => _configurationService.Get(nameof(IsMailListActionBarEnabled), false);
set => SetPropertyAndSave(nameof(IsMailListActionBarEnabled), value);
}
public bool IsShowSenderPicturesEnabled
{
get => _configurationService.Get(nameof(IsShowSenderPicturesEnabled), true);

View File

@@ -80,27 +80,26 @@ namespace Wino.Core.Services
}
else
{
bool isAllFlagged = selectedMailItems.All(a => a.IsFlagged);
bool isAllRead = selectedMailItems.All(a => a.IsRead);
bool isAllUnread = selectedMailItems.All(a => !a.IsRead);
bool isAllFlagged = selectedMailItems.All(a => a.IsFlagged);
bool isAllNotFlagged = selectedMailItems.All(a => !a.IsFlagged);
if (isAllRead)
operationList.Add(MailOperationMenuItem.Create(MailOperation.MarkAsUnread));
else
List<MailOperationMenuItem> readOperations = (isAllRead, isAllUnread) switch
{
if (!isAllUnread)
operationList.Add(MailOperationMenuItem.Create(MailOperation.MarkAsUnread));
(true, false) => [MailOperationMenuItem.Create(MailOperation.MarkAsUnread)],
(false, true) => [MailOperationMenuItem.Create(MailOperation.MarkAsRead)],
_ => [MailOperationMenuItem.Create(MailOperation.MarkAsRead), MailOperationMenuItem.Create(MailOperation.MarkAsUnread)]
};
operationList.AddRange(readOperations);
operationList.Add(MailOperationMenuItem.Create(MailOperation.MarkAsRead));
}
if (isAllFlagged)
operationList.Add(MailOperationMenuItem.Create(MailOperation.ClearFlag));
else
List<MailOperationMenuItem> flagsOperations = (isAllFlagged, isAllNotFlagged) switch
{
operationList.Add(MailOperationMenuItem.Create(MailOperation.ClearFlag));
operationList.Add(MailOperationMenuItem.Create(MailOperation.SetFlag));
}
(true, false) => [MailOperationMenuItem.Create(MailOperation.ClearFlag)],
(false, true) => [MailOperationMenuItem.Create(MailOperation.SetFlag)],
_ => [MailOperationMenuItem.Create(MailOperation.SetFlag), MailOperationMenuItem.Create(MailOperation.ClearFlag)]
};
operationList.AddRange(flagsOperations);
}
// Ignore

View File

@@ -41,8 +41,7 @@ namespace Wino.Mail.ViewModels
IRecipient<MailItemSelectionRemovedEvent>,
IRecipient<AccountSynchronizationCompleted>,
IRecipient<NewSynchronizationRequested>,
IRecipient<AccountSynchronizerStateChanged>,
IRecipient<SelectedMailItemsChanged>
IRecipient<AccountSynchronizerStateChanged>
{
private bool isChangingFolder = false;
@@ -63,6 +62,7 @@ namespace Wino.Mail.ViewModels
public ObservableCollection<MailItemViewModel> SelectedItems { get; set; } = [];
public ObservableCollection<FolderPivotViewModel> PivotFolders { get; set; } = [];
public ObservableCollection<MailOperationMenuItem> ActionItems { get; set; } = [];
private readonly SemaphoreSlim listManipulationSemepahore = new SemaphoreSlim(1);
private CancellationTokenSource listManipulationCancellationTokenSource = new CancellationTokenSource();
@@ -200,6 +200,13 @@ namespace Wino.Mail.ViewModels
};
}
private void SetupTopBarActions()
{
ActionItems.Clear();
var actions = GetAvailableMailActions(SelectedItems);
actions.ForEach(a => ActionItems.Add(a));
}
#region Properties
/// <summary>
@@ -365,7 +372,7 @@ namespace Wino.Mail.ViewModels
NotifyItemSelected();
Messenger.Send(new SelectedMailItemsChanged(SelectedItems.Count));
SetupTopBarActions();
}
private void UpdateFolderPivots()
@@ -415,19 +422,31 @@ namespace Wino.Mail.ViewModels
[RelayCommand]
public Task ExecuteHoverAction(MailOperationPreperationRequest request) => ExecuteMailOperationAsync(request);
[RelayCommand]
private async Task ExecuteTopBarAction(MailOperationMenuItem menuItem)
{
if (menuItem == null || !SelectedItems.Any()) return;
await HandleMailOperation(menuItem.Operation, SelectedItems);
}
/// <summary>
/// Executes the requested mail operation for currently selected items.
/// </summary>
/// <param name="operation">Action to execute for selected items.</param>
[RelayCommand]
private async Task MailOperationAsync(int mailOperationIndex)
private async Task ExecuteMailOperation(MailOperation mailOperation)
{
if (!SelectedItems.Any()) return;
// Commands don't like enums. So it has to be int.
var operation = (MailOperation)mailOperationIndex;
await HandleMailOperation(mailOperation, SelectedItems);
}
var package = new MailOperationPreperationRequest(operation, SelectedItems.Select(a => a.MailCopy));
private async Task HandleMailOperation(MailOperation mailOperation, IEnumerable<MailItemViewModel> mailItems)
{
if (!mailItems.Any()) return;
var package = new MailOperationPreperationRequest(mailOperation, mailItems.Select(a => a.MailCopy));
await ExecuteMailOperationAsync(package);
}
@@ -649,6 +668,8 @@ namespace Wino.Mail.ViewModels
Debug.WriteLine($"Updating {updatedMail.Id}-> {updatedMail.UniqueId}");
await MailCollection.UpdateMailCopy(updatedMail);
await ExecuteUIThread(() => { SetupTopBarActions(); });
}
protected override async void OnMailRemoved(MailCopy removedMail)
@@ -1012,7 +1033,5 @@ namespace Wino.Mail.ViewModels
await ExecuteUIThread(() => { IsAccountSynchronizerInSynchronization = isAnyAccountSynchronizing; });
}
public void Receive(SelectedMailItemsChanged message) => NotifyItemSelected();
}
}

View File

@@ -11,6 +11,8 @@
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.Segmented/Segmented/Segmented.xaml" />
<ResourceDictionary Source="/Styles/Converters.xaml" />
<ResourceDictionary Source="/Styles/FontIcons.xaml" />
<ResourceDictionary Source="/Styles/Colors.xaml" />

View File

@@ -120,7 +120,7 @@ namespace Wino.Controls.Advanced
{
args.Handled = true;
ItemDeletedCommand?.Execute((int)MailOperation.SoftDelete);
ItemDeletedCommand?.Execute(MailOperation.SoftDelete);
}
}

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,195 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
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;
using Wino.Extensions;
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,18 +0,0 @@
using System.Collections;
namespace Wino.Extensions
{
public static class EnumerableExtensions
{
public static IEnumerable OfType<T1, T2>(this IEnumerable source)
{
foreach (object item in source)
{
if (item is T1 || item is T2)
{
yield return item;
}
}
}
}
}

View File

@@ -5,7 +5,6 @@
xmlns:abstract="using:Wino.Views.Abstract"
xmlns:collections="using:CommunityToolkit.Mvvm.Collections"
xmlns:controls="using:Wino.Controls"
xmlns:controls1="using:CommunityToolkit.WinUI.Controls"
xmlns:converters="using:Wino.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:domain="using:Wino.Core.Domain"
@@ -13,11 +12,14 @@
xmlns:helpers="using:Wino.Helpers"
xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:ic="using:Microsoft.Xaml.Interactions.Core"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:listview="using:Wino.Controls.Advanced"
xmlns:local="using:Wino.Behaviors"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:menuflyouts="using:Wino.MenuFlyouts"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
xmlns:selectors="using:Wino.Selectors"
xmlns:toolkit="using:CommunityToolkit.WinUI.Controls"
xmlns:ui="using:Microsoft.Toolkit.Uwp.UI"
xmlns:viewModelData="using:Wino.Mail.ViewModels.Data"
xmlns:wino="using:Wino"
@@ -31,6 +33,28 @@
IsSourceGrouped="True"
Source="{x:Bind ViewModel.MailCollection.MailItems, Mode=OneWay}" />
<selectors:RendererCommandBarItemTemplateSelector
x:Key="RendererCommandBarItemTemplateSelector"
Archive="{StaticResource CommandBarItemArchiveTemplate}"
ClearFlag="{StaticResource CommandBarItemClearFlagTemplate}"
DarkEditor="{StaticResource CommandBarItemDarkEditorTemplate}"
Delete="{StaticResource CommandBarItemDeleteTemplate}"
Find="{StaticResource CommandBarItemFindTemplate}"
Forward="{StaticResource CommandBarItemForwardTemplate}"
LightEditor="{StaticResource CommandBarItemLightEditorTemplate}"
MarkAsRead="{StaticResource CommandBarItemMarkReadTemplate}"
MarkAsUnread="{StaticResource CommandBarItemMarkUnreadTemplate}"
Move="{StaticResource CommandBarItemMoveTemplate}"
MoveToJunk="{StaticResource CommandBarItemMoveToJunkTemplate}"
Print="{StaticResource CommandBarItemPrintTemplate}"
Reply="{StaticResource CommandBarItemReplyTemplate}"
ReplyAll="{StaticResource CommandBarItemReplyAllTemplate}"
SaveAs="{StaticResource CommandBarItemSaveTemplate}"
SeperatorTemplate="{StaticResource CommandBarItemSeperatorTemplate}"
SetFlag="{StaticResource CommandBarItemSetFlagTemplate}"
Unarchive="{StaticResource CommandBarItemUnarchiveTemplate}"
Zoom="{StaticResource CommandBarItemZoomTemplate}" />
<Thickness x:Key="ExpanderHeaderPadding">0,0,0,0</Thickness>
<Thickness x:Key="ExpanderChevronMargin">0,0,12,0</Thickness>
<Thickness x:Key="ExpanderHeaderBorderThickness">0,0,0,0</Thickness>
@@ -45,23 +69,10 @@
<SolidColorBrush x:Key="SystemControlRevealFocusVisualBrush" Color="#FF4C4A48" />
<SolidColorBrush x:Key="SystemControlFocusVisualSecondaryBrush" Color="#FFFFFFFF" />
<DataTemplate x:Key="FolderPivotTemplate" x:DataType="viewModelData:FolderPivotViewModel">
<StackPanel Orientation="Horizontal" Spacing="4">
<TextBlock Text="{x:Bind FolderTitle}" />
<TextBlock
x:Name="CountTextBlock"
VerticalAlignment="Center"
FontWeight="SemiBold"
Visibility="{x:Bind ShouldDisplaySelectedItemCount, Mode=OneWay}">
<Run Text="(" /><Run Text="{x:Bind SelectedItemCount, Mode=OneWay}" /><Run Text=")" />
</TextBlock>
</StackPanel>
</DataTemplate>
<!-- Header Templates -->
<DataTemplate x:Key="MailGroupHeaderDefaultTemplate" x:DataType="collections:IReadOnlyObservableGroup">
<Grid
Margin="2,2,16,2"
Margin="2,2,6,2"
AllowFocusOnInteraction="False"
Background="{ThemeResource MailListHeaderBackgroundColor}"
CornerRadius="6">
@@ -208,28 +219,6 @@
</selectors:MailItemDisplaySelector>
<SolidColorBrush x:Key="ButtonBackgroundDisabled">Transparent</SolidColorBrush>
<Style
x:Key="TopCommandBarButtonStyle"
BasedOn="{StaticResource DefaultButtonStyle}"
TargetType="Button">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Padding" Value="12" />
</Style>
<Style
x:Key="TopCommandBarToggleButtonStyle"
BasedOn="{StaticResource DefaultToggleButtonStyle}"
TargetType="ToggleButton">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Padding" Value="12" />
</Style>
</Page.Resources>
<wino:BasePage.ShellContent>
@@ -272,7 +261,7 @@
<Border
x:Name="MailListContainer"
Grid.Column="0"
Padding="5,0,0,0"
Padding="5,5,5,0"
Background="{ThemeResource WinoContentZoneBackgroud}"
BorderBrush="{StaticResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
@@ -284,209 +273,113 @@
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Top Area -->
<!-- Action bar -->
<Grid
Padding="2,6,4,6"
Margin="0,0,0,5"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
CornerRadius="8"
RowSpacing="4">
Visibility="{x:Bind ViewModel.PreferencesService.IsMailListActionBarEnabled}">
<CommandBar
HorizontalAlignment="Left"
DefaultLabelPosition="Collapsed"
IsEnabled="{x:Bind helpers:XamlHelpers.CountToBooleanConverter(ViewModel.SelectedItemCount), Mode=OneWay}"
OverflowButtonVisibility="Auto">
<interactivity:Interaction.Behaviors>
<local:BindableCommandBarBehavior
ItemClickedCommand="{x:Bind ViewModel.ExecuteTopBarActionCommand}"
ItemTemplateSelector="{StaticResource RendererCommandBarItemTemplateSelector}"
PrimaryCommands="{x:Bind ViewModel.ActionItems, Mode=OneWay}" />
</interactivity:Interaction.Behaviors>
</CommandBar>
</Grid>
<!-- Pivot + Sync + Multi Select -->
<Grid Grid.Row="1" Padding="0,0,0,6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Top Commands -->
<Grid
Grid.Row="0"
Padding="2,0"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
CornerRadius="8">
<!-- Commands -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button
Command="{x:Bind ViewModel.SyncFolderCommand}"
IsEnabled="{x:Bind ViewModel.CanSynchronize, Mode=OneWay}"
Style="{StaticResource TopCommandBarButtonStyle}">
<Button.Content>
<controls:WinoFontIcon FontSize="16" Icon="Sync" />
</Button.Content>
</Button>
<ToggleButton
x:Name="SelectionModeToggle"
Grid.Column="1"
Checked="SelectionModeToggleChecked"
IsChecked="{x:Bind ViewModel.IsMultiSelectionModeEnabled, Mode=TwoWay}"
Style="{StaticResource TopCommandBarToggleButtonStyle}"
Unchecked="SelectionModeToggleUnchecked">
<ToggleButton.Content>
<controls:WinoFontIcon FontSize="18" Icon="MultiSelect" />
</ToggleButton.Content>
</ToggleButton>
<AppBarSeparator Grid.Column="2" Margin="2,0" />
<Button
x:Name="ArchiveAppBarButton"
Grid.Column="3"
x:Load="{x:Bind helpers:XamlHelpers.ReverseBoolConverter(ViewModel.IsArchiveSpecialFolder), Mode=OneWay}"
Command="{x:Bind ViewModel.MailOperationCommand}"
IsEnabled="{x:Bind ViewModel.HasSelectedItems, Mode=OneWay}"
Style="{StaticResource TopCommandBarButtonStyle}"
ToolTipService.ToolTip="{x:Bind domain:Translator.MailOperation_Archive}">
<Button.Content>
<controls:WinoFontIcon FontSize="18" Icon="Archive" />
</Button.Content>
<Button.CommandParameter>
<enums:MailOperation>Archive</enums:MailOperation>
</Button.CommandParameter>
</Button>
<Button
x:Name="UnarchiveAppBarButton"
Grid.Column="3"
x:Load="{x:Bind ViewModel.IsArchiveSpecialFolder, Mode=OneWay}"
Command="{x:Bind ViewModel.MailOperationCommand}"
IsEnabled="{x:Bind ViewModel.HasSelectedItems, Mode=OneWay}"
Style="{StaticResource TopCommandBarButtonStyle}"
ToolTipService.ToolTip="{x:Bind domain:Translator.MailOperation_Unarchive}">
<Button.Content>
<controls:WinoFontIcon FontSize="18" Icon="UnArchive" />
</Button.Content>
<Button.CommandParameter>
<enums:MailOperation>UnArchive</enums:MailOperation>
</Button.CommandParameter>
</Button>
<Button
Grid.Column="4"
Command="{x:Bind ViewModel.MailOperationCommand}"
IsEnabled="{x:Bind ViewModel.HasSelectedItems, Mode=OneWay}"
Style="{StaticResource TopCommandBarButtonStyle}"
ToolTipService.ToolTip="{x:Bind domain:Translator.MailOperation_Delete}">
<Button.CommandParameter>
<enums:MailOperation>SoftDelete</enums:MailOperation>
</Button.CommandParameter>
<Button.Content>
<controls:WinoFontIcon FontSize="18" Icon="Delete" />
</Button.Content>
</Button>
<Button
x:Name="MoveButtonAppBarButton"
Grid.Column="5"
Command="{x:Bind ViewModel.MailOperationCommand}"
IsEnabled="{x:Bind ViewModel.HasSelectedItems, Mode=OneWay}"
Style="{StaticResource TopCommandBarButtonStyle}"
ToolTipService.ToolTip="{x:Bind domain:Translator.MailOperation_Move}">
<Button.CommandParameter>
<enums:MailOperation>Move</enums:MailOperation>
</Button.CommandParameter>
<Button.Content>
<controls:WinoFontIcon FontSize="18" Icon="Move" />
</Button.Content>
</Button>
<Button
Grid.Column="6"
IsEnabled="{x:Bind ViewModel.HasSelectedItems, Mode=OneWay}"
Style="{StaticResource TopCommandBarButtonStyle}">
<Button.Content>
<controls:WinoFontIcon FontSize="20" Icon="More" />
</Button.Content>
<Button.Flyout>
<MenuFlyout AreOpenCloseAnimationsEnabled="False" Placement="BottomEdgeAlignedLeft">
<MenuFlyoutItem Command="{x:Bind ViewModel.MailOperationCommand}" Text="{x:Bind domain:Translator.MailOperation_SetFlag}">
<MenuFlyoutItem.CommandParameter>
<enums:MailOperation>SetFlag</enums:MailOperation>
</MenuFlyoutItem.CommandParameter>
<MenuFlyoutItem.Icon>
<controls:WinoFontIcon Icon="Flag" />
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem Command="{x:Bind ViewModel.MailOperationCommand}" Text="{x:Bind domain:Translator.MailOperation_ClearFlag}">
<MenuFlyoutItem.CommandParameter>
<enums:MailOperation>ClearFlag</enums:MailOperation>
</MenuFlyoutItem.CommandParameter>
<MenuFlyoutItem.Icon>
<controls:WinoFontIcon Icon="ClearFlag" />
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem Command="{x:Bind ViewModel.MailOperationCommand}" Text="{x:Bind domain:Translator.MailOperation_MarkAsRead}">
<MenuFlyoutItem.CommandParameter>
<enums:MailOperation>MarkAsRead</enums:MailOperation>
</MenuFlyoutItem.CommandParameter>
<MenuFlyoutItem.Icon>
<controls:WinoFontIcon Icon="MarkRead" />
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem Command="{x:Bind ViewModel.MailOperationCommand}" Text="{x:Bind domain:Translator.MailOperation_MarkAsUnread}">
<MenuFlyoutItem.CommandParameter>
<enums:MailOperation>MarkAsUnread</enums:MailOperation>
</MenuFlyoutItem.CommandParameter>
<MenuFlyoutItem.Icon>
<controls:WinoFontIcon Icon="MarkUnread" />
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
</MenuFlyout>
</Button.Flyout>
</Button>
</Grid>
</Grid>
<!-- Pivot + Sync + Multi Select -->
<Grid
<!-- Select All Checkbox -->
<CheckBox
x:Name="SelectAllCheckbox"
Grid.Row="1"
Margin="0,0,0,5"
Visibility="{x:Bind helpers:XamlHelpers.ReverseBoolToVisibilityConverter(ViewModel.IsInSearchMode), Mode=OneWay}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
MinWidth="0"
Margin="8,0,0,0"
VerticalAlignment="Center"
Canvas.ZIndex="100"
Checked="SelectAllCheckboxChecked"
Unchecked="SelectAllCheckboxUnchecked"
Visibility="{x:Bind helpers:XamlHelpers.IsSelectionModeMultiple(MailListView.SelectionMode), Mode=OneWay}" />
<!-- Select All Checkbox -->
<CheckBox
x:Name="SelectAllCheckbox"
Grid.Row="1"
MinWidth="0"
Margin="8,0,0,0"
VerticalAlignment="Center"
Canvas.ZIndex="100"
Checked="SelectAllCheckboxChecked"
Unchecked="SelectAllCheckboxUnchecked"
Visibility="{x:Bind helpers:XamlHelpers.IsSelectionModeMultiple(MailListView.SelectionMode), Mode=OneWay}" />
<!-- Folders -->
<toolkit:Segmented
Grid.Row="1"
Grid.Column="1"
ItemsSource="{x:Bind ViewModel.PivotFolders, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.SelectedFolderPivot, Mode=TwoWay}"
SelectionChanged="FolderPivotChanged"
Style="{StaticResource PivotSegmentedStyle}">
<toolkit:Segmented.ItemTemplate>
<DataTemplate x:DataType="viewModelData:FolderPivotViewModel">
<StackPanel Orientation="Horizontal" Spacing="4">
<TextBlock Text="{x:Bind FolderTitle}" />
<TextBlock
x:Name="CountTextBlock"
VerticalAlignment="Center"
FontWeight="SemiBold"
Visibility="{x:Bind ShouldDisplaySelectedItemCount, Mode=OneWay}">
<Run Text="(" /><Run Text="{x:Bind SelectedItemCount, Mode=OneWay}" /><Run Text=")" />
</TextBlock>
</StackPanel>
</DataTemplate>
</toolkit:Segmented.ItemTemplate>
</toolkit:Segmented>
<!-- Folders -->
<controls:WinoPivotControl
x:Name="WinoPivot"
Grid.Row="1"
Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"
DataTemplate="{StaticResource FolderPivotTemplate}"
ItemsSource="{x:Bind ViewModel.PivotFolders, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.SelectedFolderPivot, Mode=TwoWay}"
SelectionChanged="FolderPivotChanged"
SelectorPipeColor="{ThemeResource NavigationViewSelectionIndicatorForeground}" />
<!-- Filtering -->
<!-- Sync + Multi Select + Filtering -->
<StackPanel
Grid.Row="1"
Grid.Column="2"
Orientation="Horizontal">
<Button
Width="36"
Height="36"
Background="Transparent"
BorderThickness="0"
Command="{x:Bind ViewModel.SyncFolderCommand}"
IsEnabled="{x:Bind ViewModel.CanSynchronize, Mode=OneWay}">
<Button.Content>
<FontIcon
FontFamily="Segoe Fluent Icons"
FontSize="14"
Glyph="&#xE895;" />
</Button.Content>
</Button>
<ToggleButton
x:Name="SelectionModeToggle"
Width="36"
Height="36"
Background="Transparent"
BorderThickness="0"
Checked="SelectionModeToggleChecked"
IsChecked="{x:Bind ViewModel.IsMultiSelectionModeEnabled, Mode=TwoWay}"
Unchecked="SelectionModeToggleUnchecked">
<ToggleButton.Content>
<FontIcon
FontFamily="Segoe Fluent Icons"
FontSize="14"
Glyph="&#xE762;" />
</ToggleButton.Content>
</ToggleButton>
<muxc:DropDownButton
Grid.Row="1"
Grid.Column="2"
Height="36"
Background="Transparent"
BorderThickness="0"
Content="{x:Bind ViewModel.SelectedFilterOption.Title, Mode=OneWay}"
ToolTipService.ToolTip="Filter">
<muxc:DropDownButton.Flyout>
@@ -502,20 +395,20 @@
SortingOptions="{x:Bind ViewModel.SortingOptions, Mode=OneTime}" />
</muxc:DropDownButton.Flyout>
</muxc:DropDownButton>
</StackPanel>
<muxc:InfoBar
Title="{x:Bind domain:Translator.InfoBarTitle_SynchronizationDisabledFolder}"
Grid.Row="0"
Grid.ColumnSpan="3"
IsClosable="True"
IsOpen="{x:Bind ViewModel.IsFolderSynchronizationEnabled, Converter={StaticResource ReverseBooleanConverter}, Mode=OneWay}"
Message="{x:Bind domain:Translator.InfoBarMessage_SynchronizationDisabledFolder}"
Severity="Informational">
<muxc:InfoBar.ActionButton>
<Button Command="{x:Bind ViewModel.EnableFolderSynchronizationCommand}" Content="Enable" />
</muxc:InfoBar.ActionButton>
</muxc:InfoBar>
</Grid>
<muxc:InfoBar
Title="{x:Bind domain:Translator.InfoBarTitle_SynchronizationDisabledFolder}"
Grid.Row="0"
Grid.ColumnSpan="3"
IsClosable="True"
IsOpen="{x:Bind ViewModel.IsFolderSynchronizationEnabled, Converter={StaticResource ReverseBooleanConverter}, Mode=OneWay}"
Message="{x:Bind domain:Translator.InfoBarMessage_SynchronizationDisabledFolder}"
Severity="Informational">
<muxc:InfoBar.ActionButton>
<Button Command="{x:Bind ViewModel.EnableFolderSynchronizationCommand}" Content="Enable" />
</muxc:InfoBar.ActionButton>
</muxc:InfoBar>
</Grid>
<!-- No items createria -->
@@ -574,7 +467,7 @@
ui:ListViewExtensions.ItemContainerStretchDirection="Horizontal"
ui:ScrollViewerExtensions.EnableMiddleClickScrolling="True"
ui:ScrollViewerExtensions.VerticalScrollBarMargin="0"
ItemDeletedCommand="{x:Bind ViewModel.MailOperationCommand}"
ItemDeletedCommand="{x:Bind ViewModel.ExecuteMailOperationCommand}"
ItemTemplateSelector="{StaticResource MailItemDisplaySelector}"
ItemsSource="{x:Bind MailCollectionViewSource.View, Mode=OneWay}"
LoadMoreCommand="{x:Bind ViewModel.LoadMoreItemsCommand}"
@@ -615,10 +508,7 @@
</ListView.Resources>
<ListView.ItemTemplate>
<DataTemplate x:DataType="ICollectionViewGroup">
<Grid
Margin="4,0"
Background="{ThemeResource MailListHeaderBackgroundColor}"
CornerRadius="4">
<Grid Background="{ThemeResource MailListHeaderBackgroundColor}" CornerRadius="4">
<TextBlock
Margin="12,0"
HorizontalAlignment="Center"
@@ -638,7 +528,7 @@
<controls:WinoInfoBar
Title="{x:Bind ViewModel.BarTitle, Mode=OneWay}"
Grid.Row="2"
Margin="6,0,6,6"
Margin="0,0,0,5"
VerticalAlignment="Bottom"
AnimationType="SlideFromBottomToTop"
DismissInterval="2"
@@ -649,7 +539,7 @@
</Grid>
</Border>
<controls1:PropertySizer
<toolkit:PropertySizer
x:Name="MailListSizer"
Grid.Column="1"
Width="16"

View File

@@ -375,7 +375,7 @@ namespace Wino.Views
{
args.Handled = true;
ViewModel?.MailOperationCommand?.Execute((int)MailOperation.SoftDelete);
ViewModel?.ExecuteMailOperationCommand?.Execute(MailOperation.SoftDelete);
}
}

File diff suppressed because one or more lines are too long

View File

@@ -141,6 +141,9 @@
<PackageReference Include="CommunityToolkit.Uwp.Behaviors">
<Version>8.1.240821</Version>
</PackageReference>
<PackageReference Include="CommunityToolkit.Uwp.Controls.Segmented">
<Version>8.1.240821</Version>
</PackageReference>
<PackageReference Include="CommunityToolkit.Uwp.Controls.SettingsControls">
<Version>8.1.240821</Version>
</PackageReference>
@@ -265,9 +268,6 @@
<Compile Include="MenuFlyouts\WinoOperationFlyout.cs" />
<Compile Include="MenuFlyouts\WinoOperationFlyoutItem.cs" />
<Compile Include="Controls\RendererCommandBar.cs" />
<Compile Include="Controls\WinoPivotControl.xaml.cs">
<DependentUpon>WinoPivotControl.xaml</DependentUpon>
</Compile>
<Compile Include="Converters\ReverseBooleanConverter.cs" />
<Compile Include="Dialogs\AccountCreationDialog.xaml.cs">
<DependentUpon>AccountCreationDialog.xaml</DependentUpon>
@@ -276,7 +276,6 @@
<Compile Include="Extensions\CompositionExtensions.Implicit.cs" />
<Compile Include="Extensions\CompositionExtensions.Size.cs" />
<Compile Include="Extensions\CompositionEnums.cs" />
<Compile Include="Extensions\EnumerableExtensions.cs" />
<Compile Include="Extensions\UtilExtensions.cs" />
<Compile Include="MenuFlyouts\FilterMenuFlyout.cs" />
<Compile Include="Controls\ImagePreviewControl.cs" />
@@ -456,10 +455,6 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\WinoPivotControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Dialogs\AccountEditDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>

View File

@@ -1,8 +0,0 @@
namespace Wino.Messaging.Client.Mails
{
/// <summary>
/// When selected mail count is changed.
/// </summary>
/// <param name="SelectedItemCount">New selected mail count.</param>
public record SelectedMailItemsChanged(int SelectedItemCount);
}