Merge main
This commit is contained in:
@@ -11,7 +11,8 @@
|
|||||||
ChangeFlag,
|
ChangeFlag,
|
||||||
AlwaysMoveTo,
|
AlwaysMoveTo,
|
||||||
MoveToFocused,
|
MoveToFocused,
|
||||||
RenameFolder
|
RenameFolder,
|
||||||
|
Archive
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI requests
|
// UI requests
|
||||||
|
|||||||
66
Wino.Core/Requests/ArchiveRequest.cs
Normal file
66
Wino.Core/Requests/ArchiveRequest.cs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
|
using MoreLinq;
|
||||||
|
using Wino.Core.Domain.Entities;
|
||||||
|
using Wino.Core.Domain.Enums;
|
||||||
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
using Wino.Core.Domain.Models.Requests;
|
||||||
|
|
||||||
|
namespace Wino.Core.Requests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Archive message request.
|
||||||
|
/// By default, the message will be moved to the Archive folder.
|
||||||
|
/// For Gmail, 'Archive' label will be removed from the message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="IsArchiving">Whether are archiving or unarchiving</param>
|
||||||
|
/// <param name="Item">Mail to archive</param>
|
||||||
|
/// <param name="FromFolder">Source folder.</param>
|
||||||
|
/// <param name="ToFolder">Optional Target folder. Required for ImapSynchronizer and OutlookSynchronizer.</param>
|
||||||
|
public record ArchiveRequest(bool IsArchiving, MailCopy Item, MailItemFolder FromFolder, MailItemFolder ToFolder = null) : RequestBase<BatchArchiveRequest>(Item, MailSynchronizerOperation.Archive), ICustomFolderSynchronizationRequest
|
||||||
|
{
|
||||||
|
public List<Guid> SynchronizationFolderIds
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var folderIds = new List<Guid> { FromFolder.Id };
|
||||||
|
|
||||||
|
if (ToFolder != null)
|
||||||
|
{
|
||||||
|
folderIds.Add(ToFolder.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return folderIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IBatchChangeRequest CreateBatch(IEnumerable<IRequest> matchingItems)
|
||||||
|
=> new BatchArchiveRequest(IsArchiving, matchingItems, FromFolder, ToFolder);
|
||||||
|
|
||||||
|
public override void ApplyUIChanges()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new MailRemovedMessage(Item));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RevertUIChanges()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new MailAddedMessage(Item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
public record BatchArchiveRequest(bool IsArchiving, IEnumerable<IRequest> Items, MailItemFolder FromFolder, MailItemFolder ToFolder = null) : BatchRequestBase(Items, MailSynchronizerOperation.Archive)
|
||||||
|
{
|
||||||
|
public override void ApplyUIChanges()
|
||||||
|
{
|
||||||
|
Items.ForEach(item => WeakReferenceMessenger.Default.Send(new MailRemovedMessage(item.Item)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RevertUIChanges()
|
||||||
|
{
|
||||||
|
Items.ForEach(item => WeakReferenceMessenger.Default.Send(new MailAddedMessage(item.Item)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -476,7 +476,11 @@ namespace Wino.Core.Services
|
|||||||
.Where(a => a.MailAccountId == options.AccountId && a.IsSynchronizationEnabled && options.SynchronizationFolderIds.Contains(a.Id))
|
.Where(a => a.MailAccountId == options.AccountId && a.IsSynchronizationEnabled && options.SynchronizationFolderIds.Contains(a.Id))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
folders.AddRange(synchronizationFolders);
|
// Order is important for moving.
|
||||||
|
// By implementation, removing mail folders must be synchronized first. Requests are made in that order for custom sync.
|
||||||
|
// eg. Moving item from Folder A to Folder B. If we start syncing Folder B first, we might miss adding assignment for Folder A.
|
||||||
|
|
||||||
|
folders.AddRange(synchronizationFolders.OrderBy(a => options.SynchronizationFolderIds.IndexOf(a.Id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return folders;
|
return folders;
|
||||||
|
|||||||
@@ -160,20 +160,37 @@ namespace Wino.Core.Services
|
|||||||
}
|
}
|
||||||
else if (action == MailOperation.Archive)
|
else if (action == MailOperation.Archive)
|
||||||
{
|
{
|
||||||
// Validate archive folder exists.
|
// For IMAP and Outlook: Validate archive folder exists.
|
||||||
|
// Gmail doesn't need archive folder existence.
|
||||||
|
|
||||||
var archiveFolder = await _folderService.GetSpecialFolderByAccountIdAsync(mailItem.AssignedAccount.Id, SpecialFolderType.Archive)
|
MailItemFolder archiveFolder = null;
|
||||||
|
|
||||||
|
bool shouldRequireArchiveFolder = mailItem.AssignedAccount.ProviderType == MailProviderType.Outlook
|
||||||
|
|| mailItem.AssignedAccount.ProviderType == MailProviderType.IMAP4
|
||||||
|
|| mailItem.AssignedAccount.ProviderType == MailProviderType.Office365;
|
||||||
|
|
||||||
|
if (shouldRequireArchiveFolder)
|
||||||
|
{
|
||||||
|
archiveFolder = await _folderService.GetSpecialFolderByAccountIdAsync(mailItem.AssignedAccount.Id, SpecialFolderType.Archive)
|
||||||
?? throw new UnavailableSpecialFolderException(SpecialFolderType.Archive, mailItem.AssignedAccount.Id);
|
?? throw new UnavailableSpecialFolderException(SpecialFolderType.Archive, mailItem.AssignedAccount.Id);
|
||||||
|
|
||||||
return new MoveRequest(mailItem, mailItem.AssignedFolder, archiveFolder);
|
|
||||||
}
|
}
|
||||||
else if (action == MailOperation.UnArchive || action == MailOperation.MarkAsNotJunk)
|
|
||||||
|
return new ArchiveRequest(true, mailItem, mailItem.AssignedFolder, archiveFolder);
|
||||||
|
}
|
||||||
|
else if (action == MailOperation.MarkAsNotJunk)
|
||||||
{
|
{
|
||||||
var inboxFolder = await _folderService.GetSpecialFolderByAccountIdAsync(mailItem.AssignedAccount.Id, SpecialFolderType.Inbox)
|
var inboxFolder = await _folderService.GetSpecialFolderByAccountIdAsync(mailItem.AssignedAccount.Id, SpecialFolderType.Inbox)
|
||||||
?? throw new UnavailableSpecialFolderException(SpecialFolderType.Inbox, mailItem.AssignedAccount.Id);
|
?? throw new UnavailableSpecialFolderException(SpecialFolderType.Inbox, mailItem.AssignedAccount.Id);
|
||||||
|
|
||||||
return new MoveRequest(mailItem, mailItem.AssignedFolder, inboxFolder);
|
return new MoveRequest(mailItem, mailItem.AssignedFolder, inboxFolder);
|
||||||
}
|
}
|
||||||
|
else if (action == MailOperation.UnArchive)
|
||||||
|
{
|
||||||
|
var inboxFolder = await _folderService.GetSpecialFolderByAccountIdAsync(mailItem.AssignedAccount.Id, SpecialFolderType.Inbox)
|
||||||
|
?? throw new UnavailableSpecialFolderException(SpecialFolderType.Inbox, mailItem.AssignedAccount.Id);
|
||||||
|
|
||||||
|
return new ArchiveRequest(false, mailItem, mailItem.AssignedFolder, inboxFolder);
|
||||||
|
}
|
||||||
else if (action == MailOperation.SoftDelete)
|
else if (action == MailOperation.SoftDelete)
|
||||||
{
|
{
|
||||||
var trashFolder = await _folderService.GetSpecialFolderByAccountIdAsync(mailItem.AssignedAccount.Id, SpecialFolderType.Deleted)
|
var trashFolder = await _folderService.GetSpecialFolderByAccountIdAsync(mailItem.AssignedAccount.Id, SpecialFolderType.Deleted)
|
||||||
|
|||||||
@@ -272,6 +272,9 @@ namespace Wino.Core.Synchronizers
|
|||||||
case MailSynchronizerOperation.CreateDraft:
|
case MailSynchronizerOperation.CreateDraft:
|
||||||
yield return CreateDraft((BatchCreateDraftRequest)item);
|
yield return CreateDraft((BatchCreateDraftRequest)item);
|
||||||
break;
|
break;
|
||||||
|
case MailSynchronizerOperation.Archive:
|
||||||
|
yield return Archive((BatchArchiveRequest)item);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -324,6 +327,7 @@ namespace Wino.Core.Synchronizers
|
|||||||
public virtual IEnumerable<IRequestBundle<TBaseRequest>> MoveToFocused(BatchMoveToFocusedRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
|
public virtual IEnumerable<IRequestBundle<TBaseRequest>> MoveToFocused(BatchMoveToFocusedRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
|
||||||
public virtual IEnumerable<IRequestBundle<TBaseRequest>> CreateDraft(BatchCreateDraftRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
|
public virtual IEnumerable<IRequestBundle<TBaseRequest>> CreateDraft(BatchCreateDraftRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
|
||||||
public virtual IEnumerable<IRequestBundle<TBaseRequest>> SendDraft(BatchSendDraftRequestRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
|
public virtual IEnumerable<IRequestBundle<TBaseRequest>> SendDraft(BatchSendDraftRequestRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
|
||||||
|
public virtual IEnumerable<IRequestBundle<TBaseRequest>> Archive(BatchArchiveRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Downloads a single missing message from synchronizer and saves it to given FileId from IMailItem.
|
/// Downloads a single missing message from synchronizer and saves it to given FileId from IMailItem.
|
||||||
|
|||||||
@@ -635,6 +635,28 @@ namespace Wino.Core.Synchronizers
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<IRequestBundle<IClientServiceRequest>> Archive(BatchArchiveRequest request)
|
||||||
|
{
|
||||||
|
return CreateBatchedHttpBundleFromGroup(request, (items) =>
|
||||||
|
{
|
||||||
|
var batchModifyRequest = new BatchModifyMessagesRequest
|
||||||
|
{
|
||||||
|
Ids = items.Select(a => a.Item.Id.ToString()).ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (request.IsArchiving)
|
||||||
|
{
|
||||||
|
batchModifyRequest.RemoveLabelIds = new[] { GoogleIntegratorExtensions.INBOX_LABEL_ID };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
batchModifyRequest.AddLabelIds = new[] { GoogleIntegratorExtensions.INBOX_LABEL_ID };
|
||||||
|
}
|
||||||
|
|
||||||
|
return _gmailService.Users.Messages.BatchModify(batchModifyRequest, "me");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public override IEnumerable<IRequestBundle<IClientServiceRequest>> SendDraft(BatchSendDraftRequestRequest request)
|
public override IEnumerable<IRequestBundle<IClientServiceRequest>> SendDraft(BatchSendDraftRequestRequest request)
|
||||||
{
|
{
|
||||||
return CreateHttpBundle(request, (item) =>
|
return CreateHttpBundle(request, (item) =>
|
||||||
|
|||||||
@@ -272,6 +272,9 @@ namespace Wino.Core.Synchronizers
|
|||||||
}, request);
|
}, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<IRequestBundle<ImapRequest>> Archive(BatchArchiveRequest request)
|
||||||
|
=> Move(new BatchMoveRequest(request.Items, request.FromFolder, request.ToFolder));
|
||||||
|
|
||||||
public override IEnumerable<IRequestBundle<ImapRequest>> SendDraft(BatchSendDraftRequestRequest request)
|
public override IEnumerable<IRequestBundle<ImapRequest>> SendDraft(BatchSendDraftRequestRequest request)
|
||||||
{
|
{
|
||||||
return CreateTaskBundle(async (ImapClient client) =>
|
return CreateTaskBundle(async (ImapClient client) =>
|
||||||
|
|||||||
@@ -572,6 +572,9 @@ namespace Wino.Core.Synchronizers
|
|||||||
return [deleteBundle, sendMailRequest];
|
return [deleteBundle, sendMailRequest];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<IRequestBundle<RequestInformation>> Archive(BatchArchiveRequest request)
|
||||||
|
=> Move(new BatchMoveRequest(request.Items, request.FromFolder, request.ToFolder));
|
||||||
|
|
||||||
public override async Task DownloadMissingMimeMessageAsync(IMailItem mailItem,
|
public override async Task DownloadMissingMimeMessageAsync(IMailItem mailItem,
|
||||||
MailKit.ITransferProgress transferProgress = null,
|
MailKit.ITransferProgress transferProgress = null,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<Identity
|
<Identity
|
||||||
Name="58272BurakKSE.WinoMailPreview"
|
Name="58272BurakKSE.WinoMailPreview"
|
||||||
Publisher="CN=51FBDAF3-E212-4149-89A2-A2636B3BC911"
|
Publisher="CN=51FBDAF3-E212-4149-89A2-A2636B3BC911"
|
||||||
Version="1.7.3.0" />
|
Version="1.7.4.0" />
|
||||||
|
|
||||||
<mp:PhoneIdentity PhoneProductId="0f6f3c1b-6ffd-4212-9c91-a16e8d1fa437" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
<mp:PhoneIdentity PhoneProductId="0f6f3c1b-6ffd-4212-9c91-a16e8d1fa437" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||||
|
|
||||||
|
|||||||
@@ -379,17 +379,23 @@
|
|||||||
</Page.Resources>
|
</Page.Resources>
|
||||||
|
|
||||||
<wino:BasePage.ShellContent>
|
<wino:BasePage.ShellContent>
|
||||||
|
<Grid>
|
||||||
|
<!-- Hidden focus receiver... -->
|
||||||
|
<TextBox
|
||||||
|
Grid.Column="1"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Opacity="0"
|
||||||
|
Visibility="Collapsed" />
|
||||||
|
|
||||||
<AutoSuggestBox
|
<AutoSuggestBox
|
||||||
x:Name="SearchBar"
|
x:Name="SearchBar"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
BorderBrush="Transparent"
|
BorderBrush="Transparent"
|
||||||
GotFocus="SearchBoxFocused"
|
GotFocus="SearchBoxFocused"
|
||||||
IsFocusEngagementEnabled="False"
|
|
||||||
IsTabStop="False"
|
|
||||||
LostFocus="SearchBarUnfocused"
|
LostFocus="SearchBarUnfocused"
|
||||||
PlaceholderText="{x:Bind domain:Translator.SearchBarPlaceholder}"
|
PlaceholderText="{x:Bind domain:Translator.SearchBarPlaceholder}"
|
||||||
QueryIcon="Find"
|
QueryIcon="Find"
|
||||||
TabIndex="1000"
|
|
||||||
Text="{x:Bind ViewModel.SearchQuery, Mode=TwoWay}"
|
Text="{x:Bind ViewModel.SearchQuery, Mode=TwoWay}"
|
||||||
TextChanged="SearchBar_TextChanged">
|
TextChanged="SearchBar_TextChanged">
|
||||||
<i:Interaction.Behaviors>
|
<i:Interaction.Behaviors>
|
||||||
@@ -398,6 +404,7 @@
|
|||||||
</ic:EventTriggerBehavior>
|
</ic:EventTriggerBehavior>
|
||||||
</i:Interaction.Behaviors>
|
</i:Interaction.Behaviors>
|
||||||
</AutoSuggestBox>
|
</AutoSuggestBox>
|
||||||
|
</Grid>
|
||||||
</wino:BasePage.ShellContent>
|
</wino:BasePage.ShellContent>
|
||||||
|
|
||||||
<Grid x:Name="RootGrid">
|
<Grid x:Name="RootGrid">
|
||||||
@@ -439,10 +446,16 @@
|
|||||||
<!-- Top Commands -->
|
<!-- Top Commands -->
|
||||||
<Grid
|
<Grid
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Padding="4"
|
Padding="2,0"
|
||||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||||
CornerRadius="8">
|
CornerRadius="8">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="48" />
|
||||||
|
<RowDefinition Height="2" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!-- Commands -->
|
<!-- Commands -->
|
||||||
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
@@ -582,6 +595,13 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
<muxc:ProgressBar
|
||||||
|
x:Name="LoadingProgressBar"
|
||||||
|
Grid.Row="1"
|
||||||
|
x:Load="{x:Bind ViewModel.IsInitializingFolder, Mode=OneWay}"
|
||||||
|
IsIndeterminate="True" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<!-- Pivot + Sync + Multi Select -->
|
<!-- Pivot + Sync + Multi Select -->
|
||||||
<Grid
|
<Grid
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
@@ -794,6 +814,9 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
IsNavigationStackEnabled="False" />
|
IsNavigationStackEnabled="False" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<VisualStateManager.VisualStateGroups>
|
<VisualStateManager.VisualStateGroups>
|
||||||
<VisualStateGroup x:Name="AdaptiveStates" CurrentStateChanged="AdaptivenessChanged">
|
<VisualStateGroup x:Name="AdaptiveStates" CurrentStateChanged="AdaptivenessChanged">
|
||||||
<VisualState x:Name="NormalState">
|
<VisualState x:Name="NormalState">
|
||||||
@@ -840,4 +863,3 @@
|
|||||||
</VisualStateManager.VisualStateGroups>
|
</VisualStateManager.VisualStateGroups>
|
||||||
</Grid>
|
</Grid>
|
||||||
</abstract:MailListPageAbstract>
|
</abstract:MailListPageAbstract>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user