Swipe action implementations.
This commit is contained in:
@@ -41,7 +41,8 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
|||||||
IRecipient<AccountSynchronizerStateChanged>,
|
IRecipient<AccountSynchronizerStateChanged>,
|
||||||
IRecipient<AccountCacheResetMessage>,
|
IRecipient<AccountCacheResetMessage>,
|
||||||
IRecipient<ThumbnailAdded>,
|
IRecipient<ThumbnailAdded>,
|
||||||
IRecipient<PropertyChangedMessage<bool>>
|
IRecipient<PropertyChangedMessage<bool>>,
|
||||||
|
IRecipient<SwipeActionRequested>
|
||||||
{
|
{
|
||||||
private bool isChangingFolder = false;
|
private bool isChangingFolder = false;
|
||||||
|
|
||||||
@@ -1126,4 +1127,28 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async void Receive(SwipeActionRequested message)
|
||||||
|
{
|
||||||
|
if (message.MailItem == null) return;
|
||||||
|
|
||||||
|
// Get mail copies based on the mail item type
|
||||||
|
IEnumerable<MailCopy> mailCopies;
|
||||||
|
|
||||||
|
if (message.MailItem is MailItemViewModel singleItem)
|
||||||
|
{
|
||||||
|
mailCopies = new[] { singleItem.MailCopy };
|
||||||
|
}
|
||||||
|
else if (message.MailItem is ThreadMailItemViewModel threadItem)
|
||||||
|
{
|
||||||
|
mailCopies = threadItem.ThreadEmails.Select(e => e.MailCopy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return; // Unknown mail item type
|
||||||
|
}
|
||||||
|
|
||||||
|
var package = new MailOperationPreperationRequest(message.Operation, mailCopies);
|
||||||
|
await ExecuteMailOperationAsync(package);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using Wino.Core.Domain.Enums;
|
||||||
|
using Wino.Mail.ViewModels.Data;
|
||||||
|
|
||||||
|
namespace Wino.Mail.ViewModels.Messages;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When a swipe action is performed on a mail item container.
|
||||||
|
/// </summary>
|
||||||
|
public record SwipeActionRequested(MailOperation Operation, IMailListItem MailItem);
|
||||||
@@ -18,35 +18,52 @@
|
|||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ControlTemplate TargetType="local:WinoThreadMailItemViewModelListViewItem">
|
<ControlTemplate TargetType="local:WinoThreadMailItemViewModelListViewItem">
|
||||||
<Grid>
|
<SwipeControl x:Name="ThreadSwipeControl" Tag="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Item}">
|
||||||
<Grid.ColumnDefinitions>
|
<SwipeControl.LeftItems>
|
||||||
<ColumnDefinition Width="8" />
|
<controls:WinoSwipeControlItems
|
||||||
<ColumnDefinition Width="*" />
|
x:Name="LeftSwipeItems"
|
||||||
</Grid.ColumnDefinitions>
|
IsRightSwipe="False"
|
||||||
|
MailItem="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Item}" />
|
||||||
|
</SwipeControl.LeftItems>
|
||||||
|
<SwipeControl.RightItems>
|
||||||
|
<controls:WinoSwipeControlItems
|
||||||
|
x:Name="RightSwipeItems"
|
||||||
|
IsRightSwipe="True"
|
||||||
|
MailItem="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Item}" />
|
||||||
|
</SwipeControl.RightItems>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="8" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="RootGrid"
|
x:Name="RootGrid"
|
||||||
Grid.ColumnSpan="2"
|
Grid.ColumnSpan="2"
|
||||||
Background="{ThemeResource ListViewItemBackground}"
|
Background="{ThemeResource ListViewItemBackground}"
|
||||||
CornerRadius="{ThemeResource ControlCornerRadius}" />
|
CornerRadius="{ThemeResource ControlCornerRadius}" />
|
||||||
<Border
|
<Border
|
||||||
x:Name="SelectionIndicator"
|
x:Name="SelectionIndicator"
|
||||||
Width="4"
|
Width="4"
|
||||||
Margin="0,16"
|
Margin="0,16"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Background="{ThemeResource ListViewItemSelectionIndicatorBrush}"
|
Background="{ThemeResource ListViewItemSelectionIndicatorBrush}"
|
||||||
CornerRadius="4"
|
CornerRadius="4"
|
||||||
Visibility="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Item.IsSelected, Mode=OneWay}" />
|
Visibility="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Item.IsSelected, Mode=OneWay}" />
|
||||||
<!-- Expandable Content -->
|
|
||||||
<ContentPresenter
|
<!-- Expandable Content -->
|
||||||
x:Name="ThreadContent"
|
<ContentPresenter
|
||||||
Grid.Column="1"
|
x:Name="ThreadContent"
|
||||||
Margin="6,0,0,0"
|
Grid.Column="1"
|
||||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
Margin="6,0,0,0"
|
||||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||||
Content="{TemplateBinding Content}"
|
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
Content="{TemplateBinding Content}"
|
||||||
ContentTransitions="{TemplateBinding ContentTransitions}" />
|
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||||
|
ContentTransitions="{TemplateBinding ContentTransitions}" />
|
||||||
|
|
||||||
|
|
||||||
|
</Grid>
|
||||||
<VisualStateManager.VisualStateGroups>
|
<VisualStateManager.VisualStateGroups>
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
<VisualStateGroup x:Name="CommonStates">
|
||||||
<VisualState x:Name="Normal" />
|
<VisualState x:Name="Normal" />
|
||||||
@@ -80,8 +97,7 @@
|
|||||||
</VisualState>
|
</VisualState>
|
||||||
</VisualStateGroup>
|
</VisualStateGroup>
|
||||||
</VisualStateManager.VisualStateGroups>
|
</VisualStateManager.VisualStateGroups>
|
||||||
</Grid>
|
</SwipeControl>
|
||||||
|
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
@@ -95,34 +111,50 @@
|
|||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ControlTemplate TargetType="local:WinoMailItemViewModelListViewItem">
|
<ControlTemplate TargetType="local:WinoMailItemViewModelListViewItem">
|
||||||
<Grid
|
<SwipeControl x:Name="MailSwipeControl" Tag="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Item}">
|
||||||
x:Name="RootGrid"
|
<SwipeControl.LeftItems>
|
||||||
Margin="0,2"
|
<controls:WinoSwipeControlItems
|
||||||
Background="{ThemeResource ListViewItemBackground}"
|
x:Name="LeftSwipeItems"
|
||||||
CornerRadius="{ThemeResource ControlCornerRadius}">
|
IsRightSwipe="False"
|
||||||
<Grid.ColumnDefinitions>
|
MailItem="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Item}" />
|
||||||
<ColumnDefinition Width="8" />
|
</SwipeControl.LeftItems>
|
||||||
<ColumnDefinition Width="*" />
|
<SwipeControl.RightItems>
|
||||||
</Grid.ColumnDefinitions>
|
<controls:WinoSwipeControlItems
|
||||||
<Border
|
x:Name="RightSwipeItems"
|
||||||
x:Name="SelectionIndicator"
|
IsRightSwipe="True"
|
||||||
Width="4"
|
MailItem="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Item}" />
|
||||||
Margin="0,16"
|
</SwipeControl.RightItems>
|
||||||
HorizontalAlignment="Center"
|
<Grid
|
||||||
Background="{ThemeResource ListViewItemSelectionIndicatorBrush}"
|
x:Name="RootGrid"
|
||||||
CornerRadius="4"
|
Margin="0,2"
|
||||||
Visibility="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Item.IsSelected, Mode=OneWay}" />
|
Background="{ThemeResource ListViewItemBackground}"
|
||||||
|
CornerRadius="{ThemeResource ControlCornerRadius}">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="8" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Border
|
||||||
|
x:Name="SelectionIndicator"
|
||||||
|
Width="4"
|
||||||
|
Margin="0,16"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Background="{ThemeResource ListViewItemSelectionIndicatorBrush}"
|
||||||
|
CornerRadius="4"
|
||||||
|
Visibility="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Item.IsSelected, Mode=OneWay}" />
|
||||||
|
|
||||||
<ContentPresenter
|
<ContentPresenter
|
||||||
x:Name="MailContent"
|
x:Name="MailContent"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="6,0,0,0"
|
Margin="6,0,0,0"
|
||||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
Content="{TemplateBinding Content}"
|
Content="{TemplateBinding Content}"
|
||||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||||
ContentTransitions="{TemplateBinding ContentTransitions}" />
|
ContentTransitions="{TemplateBinding ContentTransitions}" />
|
||||||
|
|
||||||
|
|
||||||
|
</Grid>
|
||||||
<VisualStateManager.VisualStateGroups>
|
<VisualStateManager.VisualStateGroups>
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
<VisualStateGroup x:Name="CommonStates">
|
||||||
<VisualState x:Name="Normal" />
|
<VisualState x:Name="Normal" />
|
||||||
@@ -156,7 +188,7 @@
|
|||||||
</VisualState>
|
</VisualState>
|
||||||
</VisualStateGroup>
|
</VisualStateGroup>
|
||||||
</VisualStateManager.VisualStateGroups>
|
</VisualStateManager.VisualStateGroups>
|
||||||
</Grid>
|
</SwipeControl>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Wino.Core.Domain.Enums;
|
||||||
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
using Wino.Core.WinUI;
|
||||||
|
using Wino.Helpers;
|
||||||
|
using Wino.Mail.ViewModels.Data;
|
||||||
|
|
||||||
|
namespace Wino.Controls;
|
||||||
|
|
||||||
|
public partial class WinoSwipeControlItems : SwipeItems
|
||||||
|
{
|
||||||
|
public static readonly DependencyProperty SwipeOperationProperty = DependencyProperty.Register(nameof(SwipeOperation), typeof(MailOperation), typeof(WinoSwipeControlItems), new PropertyMetadata(default(MailOperation), new PropertyChangedCallback(OnItemsChanged)));
|
||||||
|
public static readonly DependencyProperty MailItemProperty = DependencyProperty.Register(nameof(MailItem), typeof(IMailListItem), typeof(WinoSwipeControlItems), new PropertyMetadata(null));
|
||||||
|
public static readonly DependencyProperty IsRightSwipeProperty = DependencyProperty.Register(nameof(IsRightSwipe), typeof(bool), typeof(WinoSwipeControlItems), new PropertyMetadata(false, new PropertyChangedCallback(OnItemsChanged)));
|
||||||
|
|
||||||
|
public WinoSwipeControlItems()
|
||||||
|
{
|
||||||
|
var preferencesService = WinoApplication.Current.Services.GetRequiredService<IPreferencesService>();
|
||||||
|
|
||||||
|
SwipeOperation = IsRightSwipe ? preferencesService.RightSwipeOperation : preferencesService.LeftSwipeOperation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMailListItem MailItem
|
||||||
|
{
|
||||||
|
get { return (IMailListItem)GetValue(MailItemProperty); }
|
||||||
|
set { SetValue(MailItemProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public MailOperation SwipeOperation
|
||||||
|
{
|
||||||
|
get { return (MailOperation)GetValue(SwipeOperationProperty); }
|
||||||
|
set { SetValue(SwipeOperationProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsRightSwipe
|
||||||
|
{
|
||||||
|
get { return (bool)GetValue(IsRightSwipeProperty); }
|
||||||
|
set { SetValue(IsRightSwipeProperty, 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.ThreadEmails.All(a => a.IsRead))
|
||||||
|
finalOperation = MailOperation.MarkAsUnread;
|
||||||
|
else if (operation == MailOperation.MarkAsUnread && threadItem.ThreadEmails.All(a => !a.IsRead))
|
||||||
|
finalOperation = MailOperation.MarkAsRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
var item = new SwipeItem()
|
||||||
|
{
|
||||||
|
IconSource = new WinoFontIconSource() { Icon = XamlHelpers.GetWinoIconGlyph(finalOperation) },
|
||||||
|
Text = XamlHelpers.GetOperationString(finalOperation),
|
||||||
|
};
|
||||||
|
|
||||||
|
item.Invoked += SwipeItemInvoked;
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SwipeItemInvoked(SwipeItem sender, SwipeItemInvokedEventArgs args)
|
||||||
|
{
|
||||||
|
var swipeControl = args.SwipeControl;
|
||||||
|
swipeControl.Close();
|
||||||
|
|
||||||
|
if (MailItem == null) return;
|
||||||
|
|
||||||
|
// Determine the final operation based on current settings and mail item state
|
||||||
|
var finalOperation = SwipeOperation;
|
||||||
|
|
||||||
|
bool isSingleItem = MailItem is MailItemViewModel;
|
||||||
|
|
||||||
|
if (isSingleItem)
|
||||||
|
{
|
||||||
|
var singleItem = MailItem as MailItemViewModel;
|
||||||
|
|
||||||
|
if (SwipeOperation == MailOperation.MarkAsRead && singleItem.IsRead)
|
||||||
|
finalOperation = MailOperation.MarkAsUnread;
|
||||||
|
else if (SwipeOperation == MailOperation.MarkAsUnread && !singleItem.IsRead)
|
||||||
|
finalOperation = MailOperation.MarkAsRead;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var threadItem = MailItem as ThreadMailItemViewModel;
|
||||||
|
|
||||||
|
if (SwipeOperation == MailOperation.MarkAsRead && threadItem.ThreadEmails.All(a => a.IsRead))
|
||||||
|
finalOperation = MailOperation.MarkAsUnread;
|
||||||
|
else if (SwipeOperation == MailOperation.MarkAsUnread && threadItem.ThreadEmails.All(a => !a.IsRead))
|
||||||
|
finalOperation = MailOperation.MarkAsRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send message to MailListPageViewModel to handle the operation
|
||||||
|
CommunityToolkit.Mvvm.Messaging.WeakReferenceMessenger.Default.Send(new Mail.ViewModels.Messages.SwipeActionRequested(finalOperation, MailItem));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user