Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24c8cfd402 | ||
|
|
8257b0b582 | ||
|
|
e612f2c281 | ||
|
|
155df59b1d | ||
|
|
6efab9f386 | ||
|
|
422105a507 | ||
|
|
d58438ab1d | ||
|
|
209aa1a89f | ||
|
|
07ac81583e | ||
|
|
ee6249bb17 | ||
|
|
b8ca3f8604 | ||
|
|
85b5469d96 | ||
|
|
d3ddf7b191 | ||
|
|
ebf196ec73 | ||
|
|
85c3833452 | ||
|
|
8fb4735fc2 | ||
|
|
6bb09f10d2 | ||
|
|
a4ff67e8f4 | ||
|
|
b9a1756f90 | ||
|
|
72ff8e67ed | ||
|
|
d7006365eb | ||
|
|
86ef78b296 | ||
|
|
0d84e409c5 | ||
|
|
17c7b33167 | ||
|
|
856e1613a0 | ||
|
|
8db34289a7 | ||
|
|
3016f70349 | ||
|
|
bdf212fdb3 | ||
|
|
c6216f54f8 | ||
|
|
945c747e3e | ||
|
|
552fca8df7 | ||
|
|
4dac160619 | ||
|
|
fc0e746e1b | ||
|
|
8374b5fc0c | ||
|
|
f002ccfa3a | ||
|
|
f4bbf6eb73 |
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Wino.Core.Domain.Entities;
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
|
||||
namespace Wino.Core.Domain.Interfaces
|
||||
@@ -12,7 +13,7 @@ namespace Wino.Core.Domain.Interfaces
|
||||
/// </summary>
|
||||
/// <param name="items">Original mails.</param>
|
||||
/// <returns>Original mails with thread mails.</returns>
|
||||
Task<List<IMailItem>> ThreadItemsAsync(List<MailCopy> items);
|
||||
Task<List<IMailItem>> ThreadItemsAsync(List<MailCopy> items, IMailItemFolder threadingForFolder);
|
||||
bool ShouldThreadWithItem(IMailItem originalItem, IMailItem targetItem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,19 +14,19 @@ namespace Wino.Core.Domain.Models.MailItem
|
||||
public IMailItem LatestMailItem => ThreadItems.LastOrDefault();
|
||||
public IMailItem FirstMailItem => ThreadItems.FirstOrDefault();
|
||||
|
||||
public void AddThreadItem(IMailItem item)
|
||||
public bool AddThreadItem(IMailItem item)
|
||||
{
|
||||
if (item == null) return;
|
||||
if (item == null) return false;
|
||||
|
||||
if (ThreadItems.Any(a => a.Id == item.Id))
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item != null && item.IsDraft)
|
||||
{
|
||||
ThreadItems.Insert(0, item);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
var insertItem = ThreadItems.FirstOrDefault(a => !a.IsDraft && a.CreationDate < item.CreationDate);
|
||||
@@ -39,6 +39,8 @@ namespace Wino.Core.Domain.Models.MailItem
|
||||
|
||||
ThreadItems.Insert(index, item);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public IEnumerable<Guid> GetContainingIds() => ThreadItems?.Select(a => a.UniqueId) ?? default;
|
||||
|
||||
@@ -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",
|
||||
|
||||
14
Wino.Core.Domain/Translator.Designer.cs
generated
14
Wino.Core.Domain/Translator.Designer.cs
generated
@@ -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");
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -180,7 +180,7 @@ namespace Wino.Core.Extensions
|
||||
|
||||
// Some headers also require to start with X- or x-.
|
||||
|
||||
string[] headersToIgnore = ["Date", "To", "MIME-Version", "From", "Subject", "Message-Id"];
|
||||
string[] headersToIgnore = ["Date", "To", "Cc", "Bcc", "MIME-Version", "From", "Subject", "Message-Id"];
|
||||
string[] headersToModify = ["In-Reply-To", "Reply-To", "References", "Thread-Topic"];
|
||||
|
||||
var headers = new List<InternetMessageHeader>();
|
||||
@@ -191,15 +191,12 @@ namespace Wino.Core.Extensions
|
||||
{
|
||||
if (!headersToIgnore.Contains(header.Field))
|
||||
{
|
||||
if (headersToModify.Contains(header.Field))
|
||||
{
|
||||
headers.Add(new InternetMessageHeader() { Name = $"X-{header.Field}", Value = header.Value });
|
||||
}
|
||||
else
|
||||
{
|
||||
headers.Add(new InternetMessageHeader() { Name = header.Field, Value = header.Value });
|
||||
}
|
||||
var headerName = headersToModify.Contains(header.Field) ? $"X-{header.Field}" : header.Field;
|
||||
|
||||
// No header value should exceed 995 characters.
|
||||
var headerValue = header.Value.Length >= 995 ? header.Value.Substring(0, 995) : header.Value;
|
||||
|
||||
headers.Add(new InternetMessageHeader() { Name = headerName, Value = headerValue });
|
||||
includedHeaderCount++;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace Wino.Core.Integration.Processors
|
||||
{
|
||||
Task UpdateAccountAsync(MailAccount account);
|
||||
Task<string> UpdateAccountDeltaSynchronizationIdentifierAsync(Guid accountId, string deltaSynchronizationIdentifier);
|
||||
Task CreateAssignmentAsync(Guid accountId, string mailCopyId, string remoteFolderId);
|
||||
Task DeleteAssignmentAsync(Guid accountId, string mailCopyId, string remoteFolderId);
|
||||
Task ChangeMailReadStatusAsync(string mailCopyId, bool isRead);
|
||||
Task ChangeFlagStatusAsync(string mailCopyId, bool isFlagged);
|
||||
@@ -53,6 +52,7 @@ namespace Wino.Core.Integration.Processors
|
||||
public interface IGmailChangeProcessor : IDefaultChangeProcessor
|
||||
{
|
||||
Task MapLocalDraftAsync(string mailCopyId, string newDraftId, string newThreadId);
|
||||
Task CreateAssignmentAsync(Guid accountId, string mailCopyId, string remoteFolderId);
|
||||
}
|
||||
|
||||
public interface IOutlookChangeProcessor : IDefaultChangeProcessor
|
||||
@@ -135,8 +135,7 @@ namespace Wino.Core.Integration.Processors
|
||||
public Task DeleteAssignmentAsync(Guid accountId, string mailCopyId, string remoteFolderId)
|
||||
=> MailService.DeleteAssignmentAsync(accountId, mailCopyId, remoteFolderId);
|
||||
|
||||
public Task CreateAssignmentAsync(Guid accountId, string mailCopyId, string remoteFolderId)
|
||||
=> MailService.CreateAssignmentAsync(accountId, mailCopyId, remoteFolderId);
|
||||
|
||||
|
||||
public Task DeleteMailAsync(Guid accountId, string mailId)
|
||||
=> MailService.DeleteMailAsync(accountId, mailId);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Services;
|
||||
|
||||
@@ -12,5 +13,8 @@ namespace Wino.Core.Integration.Processors
|
||||
|
||||
public Task MapLocalDraftAsync(string mailCopyId, string newDraftId, string newThreadId)
|
||||
=> MailService.MapLocalDraftAsync(mailCopyId, newDraftId, newThreadId);
|
||||
|
||||
public Task CreateAssignmentAsync(Guid accountId, string mailCopyId, string remoteFolderId)
|
||||
=> MailService.CreateAssignmentAsync(accountId, mailCopyId, remoteFolderId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||
using Wino.Core.Domain.Entities;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
using Wino.Core.Services;
|
||||
|
||||
@@ -27,7 +28,7 @@ namespace Wino.Core.Integration.Threading
|
||||
}
|
||||
|
||||
///<inheritdoc/>
|
||||
public async Task<List<IMailItem>> ThreadItemsAsync(List<MailCopy> items)
|
||||
public async Task<List<IMailItem>> ThreadItemsAsync(List<MailCopy> items, IMailItemFolder threadingForFolder)
|
||||
{
|
||||
var assignedAccount = items[0].AssignedAccount;
|
||||
|
||||
@@ -62,11 +63,43 @@ namespace Wino.Core.Integration.Threading
|
||||
}
|
||||
|
||||
var thread = new ThreadMailItem();
|
||||
|
||||
foreach (var childThreadItem in threadItem)
|
||||
{
|
||||
thread.AddThreadItem(childThreadItem);
|
||||
if (thread.ThreadItems.Any(a => a.Id == childThreadItem.Id))
|
||||
{
|
||||
// Mail already exist in the thread.
|
||||
// There should be only 1 instance of the mail in the thread.
|
||||
// Make sure we add the correct one.
|
||||
|
||||
// Add the one with threading folder.
|
||||
var threadingFolderItem = threadItem.FirstOrDefault(a => a.Id == childThreadItem.Id && a.FolderId == threadingForFolder.Id);
|
||||
|
||||
if (threadingFolderItem == null) continue;
|
||||
|
||||
// Remove the existing one.
|
||||
thread.ThreadItems.Remove(thread.ThreadItems.First(a => a.Id == childThreadItem.Id));
|
||||
|
||||
// Add the correct one for listing.
|
||||
thread.AddThreadItem(threadingFolderItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
thread.AddThreadItem(childThreadItem);
|
||||
}
|
||||
}
|
||||
|
||||
if (thread.ThreadItems.Count > 1)
|
||||
{
|
||||
resultList.Add(thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't make threads if the thread has only one item.
|
||||
// Gmail has may have multiple assignments for the same item.
|
||||
|
||||
resultList.Add(thread.ThreadItems.First());
|
||||
}
|
||||
resultList.Add(thread);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||
using SqlKata;
|
||||
using Wino.Core.Domain.Entities;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
using Wino.Core.Extensions;
|
||||
using Wino.Core.Services;
|
||||
@@ -58,7 +59,7 @@ namespace Wino.Core.Integration.Threading
|
||||
return _databaseService.Connection.FindWithQueryAsync<MailCopy>(query.GetRawQuery());
|
||||
}
|
||||
|
||||
public async Task<List<IMailItem>> ThreadItemsAsync(List<MailCopy> items)
|
||||
public async Task<List<IMailItem>> ThreadItemsAsync(List<MailCopy> items, IMailItemFolder threadingForFolder)
|
||||
{
|
||||
var threads = new List<ThreadMailItem>();
|
||||
|
||||
|
||||
@@ -192,10 +192,12 @@ namespace Wino.Core.MenuItems
|
||||
item.IsExpanded = false;
|
||||
item.IsSelected = false;
|
||||
|
||||
Remove(item);
|
||||
try
|
||||
{
|
||||
Remove(item);
|
||||
}
|
||||
catch (Exception) { }
|
||||
});
|
||||
|
||||
// RemoveRange(itemsToRemove);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Wino.Core.Requests
|
||||
Items.ForEach(item => WeakReferenceMessenger.Default.Send(new MailAddedMessage(item.Item)));
|
||||
}
|
||||
|
||||
public override int ResynchronizationDelay => 10000;
|
||||
public override int ResynchronizationDelay => 6000;
|
||||
public override bool ExecuteSerialBatch => true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -241,7 +241,7 @@ namespace Wino.Core.Services
|
||||
|
||||
// Only thread items from Draft and Sent folders must present here.
|
||||
// Otherwise this strategy will fetch the items that are in Deleted folder as well.
|
||||
var accountThreadedItems = await threadingStrategy.ThreadItemsAsync([.. group]);
|
||||
var accountThreadedItems = await threadingStrategy.ThreadItemsAsync([.. group], options.Folders.First());
|
||||
|
||||
// Populate threaded items with folder and account assignments.
|
||||
// Almost everything already should be in cache from initial population.
|
||||
@@ -298,7 +298,11 @@ namespace Wino.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
bool isContactCached = contactCache.TryGetValue(mailCopy.FromAddress, out AccountContact contactAssignment);
|
||||
AccountContact contactAssignment = null;
|
||||
|
||||
bool isContactCached = !string.IsNullOrEmpty(mailCopy.FromAddress) ?
|
||||
contactCache.TryGetValue(mailCopy.FromAddress, out contactAssignment) :
|
||||
false;
|
||||
|
||||
if (!isContactCached && accountAssignment != null)
|
||||
{
|
||||
@@ -312,11 +316,33 @@ namespace Wino.Core.Services
|
||||
|
||||
mailCopy.AssignedFolder = folderAssignment;
|
||||
mailCopy.AssignedAccount = accountAssignment;
|
||||
mailCopy.SenderContact = contactAssignment ?? new AccountContact() { Name = mailCopy.FromName, Address = mailCopy.FromAddress };
|
||||
mailCopy.SenderContact = contactAssignment ?? CreateUnknownContact(mailCopy.FromName, mailCopy.FromAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AccountContact CreateUnknownContact(string fromName, string fromAddress)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fromName) && string.IsNullOrEmpty(fromAddress))
|
||||
{
|
||||
return new AccountContact()
|
||||
{
|
||||
Name = Translator.UnknownSender,
|
||||
Address = Translator.UnknownAddress
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(fromName)) fromName = fromAddress;
|
||||
|
||||
return new AccountContact()
|
||||
{
|
||||
Name = fromName,
|
||||
Address = fromAddress
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<MailCopy>> GetMailItemsAsync(string mailCopyId)
|
||||
{
|
||||
var mailCopies = await Connection.Table<MailCopy>().Where(a => a.Id == mailCopyId).ToListAsync();
|
||||
@@ -409,12 +435,11 @@ namespace Wino.Core.Services
|
||||
|
||||
foreach (var mailItem in allMails)
|
||||
{
|
||||
await DeleteMailInternalAsync(mailItem).ConfigureAwait(false);
|
||||
|
||||
// Delete mime file.
|
||||
// Delete mime file as well.
|
||||
// Even though Gmail might have multiple copies for the same mail, we only have one MIME file for all.
|
||||
// Their FileId is inserted same.
|
||||
await _mimeFileService.DeleteMimeMessageAsync(accountId, mailItem.FileId);
|
||||
|
||||
await DeleteMailInternalAsync(mailItem, preserveMimeFile: false).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,7 +482,7 @@ namespace Wino.Core.Services
|
||||
ReportUIChange(new MailUpdatedMessage(mailCopy));
|
||||
}
|
||||
|
||||
private async Task DeleteMailInternalAsync(MailCopy mailCopy)
|
||||
private async Task DeleteMailInternalAsync(MailCopy mailCopy, bool preserveMimeFile)
|
||||
{
|
||||
if (mailCopy == null)
|
||||
{
|
||||
@@ -473,7 +498,7 @@ namespace Wino.Core.Services
|
||||
// If there are no more copies exists of the same mail, delete the MIME file as well.
|
||||
var isMailExists = await IsMailExistsAsync(mailCopy.Id).ConfigureAwait(false);
|
||||
|
||||
if (!isMailExists)
|
||||
if (!isMailExists && !preserveMimeFile)
|
||||
{
|
||||
await _mimeFileService.DeleteMimeMessageAsync(mailCopy.AssignedAccount.Id, mailCopy.FileId).ConfigureAwait(false);
|
||||
}
|
||||
@@ -554,6 +579,19 @@ namespace Wino.Core.Services
|
||||
return;
|
||||
}
|
||||
|
||||
if (mailCopy.AssignedFolder.SpecialFolderType == SpecialFolderType.Sent &&
|
||||
localFolder.SpecialFolderType == SpecialFolderType.Deleted)
|
||||
{
|
||||
// Sent item is deleted.
|
||||
// Gmail does not delete the sent items, but moves them to the deleted folder.
|
||||
// API doesn't allow removing Sent label.
|
||||
// Here we intercept this behavior, removing the Sent copy of the mail and adding the Deleted copy.
|
||||
// This way item will only be visible in Trash folder as in Gmail Web UI.
|
||||
// Don't delete MIME file since if exists.
|
||||
|
||||
await DeleteMailInternalAsync(mailCopy, preserveMimeFile: true).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// Copy one of the mail copy and assign it to the new folder.
|
||||
// We don't need to create a new MIME pack.
|
||||
// Therefore FileId is not changed for the new MailCopy.
|
||||
@@ -585,7 +623,7 @@ namespace Wino.Core.Services
|
||||
return;
|
||||
}
|
||||
|
||||
await DeleteMailInternalAsync(mailItem).ConfigureAwait(false);
|
||||
await DeleteMailInternalAsync(mailItem, preserveMimeFile: false).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<bool> CreateMailAsync(Guid accountId, NewMailItemPackage package)
|
||||
|
||||
@@ -595,13 +595,23 @@ namespace Wino.Core.Synchronizers
|
||||
{
|
||||
return CreateBatchedHttpBundleFromGroup(request, (items) =>
|
||||
{
|
||||
// Sent label can't be removed from mails for Gmail.
|
||||
// They are automatically assigned by Gmail.
|
||||
// When you delete sent mail from gmail web portal, it's moved to Trash
|
||||
// but still has Sent label. It's just hidden from the user.
|
||||
// Proper assignments will be done later on CreateAssignment call to mimic this behavior.
|
||||
var batchModifyRequest = new BatchModifyMessagesRequest
|
||||
{
|
||||
Ids = items.Select(a => a.Item.Id.ToString()).ToList(),
|
||||
AddLabelIds = new[] { request.ToFolder.RemoteFolderId },
|
||||
RemoveLabelIds = new[] { request.FromFolder.RemoteFolderId }
|
||||
AddLabelIds = [request.ToFolder.RemoteFolderId]
|
||||
};
|
||||
|
||||
// Only add remove label ids if the source folder is not sent folder.
|
||||
if (request.FromFolder.SpecialFolderType != SpecialFolderType.Sent)
|
||||
{
|
||||
batchModifyRequest.RemoveLabelIds = [request.FromFolder.RemoteFolderId];
|
||||
}
|
||||
|
||||
return _gmailService.Users.Messages.BatchModify(batchModifyRequest, "me");
|
||||
});
|
||||
}
|
||||
@@ -793,6 +803,8 @@ namespace Wino.Core.Synchronizers
|
||||
|
||||
var bundleRequestCount = bundle.Count();
|
||||
|
||||
var bundleTasks = new List<Task>();
|
||||
|
||||
for (int k = 0; k < bundleRequestCount; k++)
|
||||
{
|
||||
var requestBundle = bundle.ElementAt(k);
|
||||
@@ -802,37 +814,40 @@ namespace Wino.Core.Synchronizers
|
||||
|
||||
request.ApplyUIChanges();
|
||||
|
||||
// TODO: Queue is synchronous. Create a task bucket to await all processing.
|
||||
nativeBatchRequest.Queue<object>(nativeRequest, async (content, error, index, message)
|
||||
=> await ProcessSingleNativeRequestResponseAsync(requestBundle, error, message, cancellationToken).ConfigureAwait(false));
|
||||
nativeBatchRequest.Queue<object>(nativeRequest, (content, error, index, message)
|
||||
=> bundleTasks.Add(ProcessSingleNativeRequestResponseAsync(requestBundle, error, message, cancellationToken)));
|
||||
}
|
||||
|
||||
await nativeBatchRequest.ExecuteAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await Task.WhenAll(bundleTasks);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessGmailRequestError(RequestError error)
|
||||
private void ProcessGmailRequestError(RequestError error, IRequestBundle<IClientServiceRequest> bundle)
|
||||
{
|
||||
if (error == null) return;
|
||||
|
||||
// OutOfMemoryException is a known bug in Gmail SDK.
|
||||
if (error.Code == 0)
|
||||
{
|
||||
bundle?.Request.RevertUIChanges();
|
||||
throw new OutOfMemoryException(error.Message);
|
||||
}
|
||||
|
||||
// Entity not found.
|
||||
if (error.Code == 404)
|
||||
{
|
||||
bundle?.Request.RevertUIChanges();
|
||||
throw new SynchronizerEntityNotFoundException(error.Message);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(error.Message))
|
||||
{
|
||||
bundle?.Request.RevertUIChanges();
|
||||
error.Errors?.ForEach(error => _logger.Error("Unknown Gmail SDK error for {Name}\n{Error}", Account.Name, error));
|
||||
|
||||
// TODO: Debug
|
||||
// throw new SynchronizerException(error.Message);
|
||||
throw new SynchronizerException(error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -851,7 +866,7 @@ namespace Wino.Core.Synchronizers
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessGmailRequestError(error);
|
||||
ProcessGmailRequestError(error, null);
|
||||
}
|
||||
catch (OutOfMemoryException)
|
||||
{
|
||||
@@ -900,7 +915,7 @@ namespace Wino.Core.Synchronizers
|
||||
HttpResponseMessage httpResponseMessage,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ProcessGmailRequestError(error);
|
||||
ProcessGmailRequestError(error, bundle);
|
||||
|
||||
if (bundle is HttpRequestBundle<IClientServiceRequest, Message> messageBundle)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" />
|
||||
@@ -19,7 +21,9 @@
|
||||
<ResourceDictionary Source="/Styles/CommandBarItems.xaml" />
|
||||
<ResourceDictionary Source="/Styles/ItemContainerStyles.xaml" />
|
||||
<ResourceDictionary Source="/Styles/WinoInfoBar.xaml" />
|
||||
|
||||
<styles:CustomMessageDialogStyles />
|
||||
<styles:WinoExpanderStyle />
|
||||
|
||||
<ResourceDictionary>
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using MoreLinq;
|
||||
using Serilog;
|
||||
using Windows.UI.Xaml;
|
||||
@@ -48,8 +48,15 @@ namespace Wino.Controls.Advanced
|
||||
set { SetValue(LoadMoreCommandProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsThreadScrollingEnabled
|
||||
{
|
||||
get { return (bool)GetValue(IsThreadScrollingEnabledProperty); }
|
||||
set { SetValue(IsThreadScrollingEnabledProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsThreadScrollingEnabledProperty = DependencyProperty.Register(nameof(IsThreadScrollingEnabled), typeof(bool), typeof(WinoListView), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty LoadMoreCommandProperty = DependencyProperty.Register(nameof(LoadMoreCommand), typeof(ICommand), typeof(WinoListView), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty IsThreadListViewProperty = DependencyProperty.Register(nameof(IsThreadListView), typeof(bool), typeof(WinoListView), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty IsThreadListViewProperty = DependencyProperty.Register(nameof(IsThreadListView), typeof(bool), typeof(WinoListView), new PropertyMetadata(false, new PropertyChangedCallback(OnIsThreadViewChanged)));
|
||||
public static readonly DependencyProperty ItemDeletedCommandProperty = DependencyProperty.Register(nameof(ItemDeletedCommand), typeof(ICommand), typeof(WinoListView), new PropertyMetadata(null));
|
||||
|
||||
public WinoListView()
|
||||
@@ -65,7 +72,6 @@ namespace Wino.Controls.Advanced
|
||||
DragItemsCompleted += ItemDragCompleted;
|
||||
DragItemsStarting += ItemDragStarting;
|
||||
SelectionChanged += SelectedItemsChanged;
|
||||
ItemClick += MailItemClicked;
|
||||
ProcessKeyboardAccelerators += ProcessDelKey;
|
||||
}
|
||||
|
||||
@@ -85,6 +91,22 @@ namespace Wino.Controls.Advanced
|
||||
internalScrollviewer.ViewChanged += InternalScrollVeiwerViewChanged;
|
||||
}
|
||||
|
||||
private static void OnIsThreadViewChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (obj is WinoListView winoListView)
|
||||
{
|
||||
winoListView.AdjustThreadViewContainerVisuals();
|
||||
}
|
||||
}
|
||||
|
||||
private void AdjustThreadViewContainerVisuals()
|
||||
{
|
||||
if (IsThreadListView)
|
||||
{
|
||||
ItemContainerTransitions.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private double lastestRaisedOffset = 0;
|
||||
private int lastItemSize = 0;
|
||||
|
||||
@@ -120,7 +142,7 @@ namespace Wino.Controls.Advanced
|
||||
{
|
||||
args.Handled = true;
|
||||
|
||||
ItemDeletedCommand?.Execute((int)MailOperation.SoftDelete);
|
||||
ItemDeletedCommand?.Execute(MailOperation.SoftDelete);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,19 +182,6 @@ namespace Wino.Controls.Advanced
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -294,6 +303,10 @@ namespace Wino.Controls.Advanced
|
||||
removedMailItemViewModel.IsSelected = false;
|
||||
WeakReferenceMessenger.Default.Send(new MailItemSelectionRemovedEvent(removedMailItemViewModel));
|
||||
}
|
||||
else if (removedItem is ThreadMailItemViewModel removedThreadItemViewModel)
|
||||
{
|
||||
removedThreadItemViewModel.IsThreadExpanded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,10 +324,19 @@ namespace Wino.Controls.Advanced
|
||||
}
|
||||
else if (addedItem is ThreadMailItemViewModel threadMailItemViewModel)
|
||||
{
|
||||
threadMailItemViewModel.IsThreadExpanded = true;
|
||||
if (IsThreadScrollingEnabled)
|
||||
{
|
||||
if (internalScrollviewer != null && ContainerFromItem(threadMailItemViewModel) is FrameworkElement threadFrameworkElement)
|
||||
{
|
||||
internalScrollviewer.ScrollToElement(threadFrameworkElement, true, true, bringToTopOrLeft: true);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't select thread containers.
|
||||
SelectedItems.Remove(addedItem);
|
||||
// Try to select first item.
|
||||
if (GetThreadInternalListView(threadMailItemViewModel) is WinoListView internalListView)
|
||||
{
|
||||
internalListView.SelectFirstItem();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -336,16 +358,23 @@ namespace Wino.Controls.Advanced
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SelectionMode == ListViewSelectionMode.Extended && SelectedItems.Count == 1)
|
||||
{
|
||||
// Tell main list view to unselect all his items.
|
||||
}
|
||||
|
||||
if (SelectedItems[0] is MailItemViewModel selectedMailItemViewModel)
|
||||
public async void SelectFirstItem()
|
||||
{
|
||||
if (Items.Count > 0)
|
||||
{
|
||||
if (Items[0] is MailItemViewModel firstMailItemViewModel)
|
||||
{
|
||||
// Make sure the invisible container is realized.
|
||||
await Task.Delay(250);
|
||||
|
||||
if (ContainerFromItem(firstMailItemViewModel) is ListViewItem firstItemContainer)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new ResetSingleMailItemSelectionEvent(selectedMailItemViewModel));
|
||||
firstItemContainer.IsSelected = true;
|
||||
}
|
||||
|
||||
firstMailItemViewModel.IsSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -356,7 +385,7 @@ namespace Wino.Controls.Advanced
|
||||
|
||||
if (itemContainer is ListViewItem listItem)
|
||||
{
|
||||
var expander = listItem.GetChildByName<Expander>("ThreadExpander");
|
||||
var expander = listItem.GetChildByName<WinoExpander>("ThreadExpander");
|
||||
|
||||
if (expander != null)
|
||||
return expander.Content as WinoListView;
|
||||
@@ -370,7 +399,6 @@ namespace Wino.Controls.Advanced
|
||||
DragItemsCompleted -= ItemDragCompleted;
|
||||
DragItemsStarting -= ItemDragStarting;
|
||||
SelectionChanged -= SelectedItemsChanged;
|
||||
ItemClick -= MailItemClicked;
|
||||
ProcessKeyboardAccelerators -= ProcessDelKey;
|
||||
|
||||
if (internalScrollviewer != null)
|
||||
|
||||
@@ -80,8 +80,6 @@ namespace Wino.Controls
|
||||
control.UpdateInformation();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private async void UpdateInformation()
|
||||
{
|
||||
if (KnownHostImage == null || InitialsGrid == null || InitialsTextblock == null || (string.IsNullOrEmpty(FromName) && string.IsNullOrEmpty(FromAddress)))
|
||||
|
||||
@@ -2,15 +2,21 @@
|
||||
x:Class="Wino.Controls.MailItemDisplayInformationControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals"
|
||||
xmlns:controls="using:Wino.Controls"
|
||||
xmlns:enums="using:Wino.Core.Domain.Enums"
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
xmlns:enums="using:Wino.Core.Domain.Enums"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
FocusVisualMargin="8"
|
||||
FocusVisualPrimaryBrush="{StaticResource SystemControlRevealFocusVisualBrush}"
|
||||
FocusVisualPrimaryThickness="2"
|
||||
FocusVisualSecondaryBrush="{StaticResource SystemControlFocusVisualSecondaryBrush}"
|
||||
FocusVisualSecondaryThickness="1"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
PointerEntered="ControlPointerEntered"
|
||||
PointerExited="ControlPointerExited">
|
||||
|
||||
@@ -25,26 +31,24 @@
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid Background="Transparent" Tapped="ThreadHeaderTapped">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition x:Name="ContainerHeight" Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid>
|
||||
<Grid
|
||||
x:Name="RootContainer"
|
||||
Padding="0,1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
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}" />
|
||||
Canvas.ZIndex="9999"
|
||||
Fill="{ThemeResource SystemAccentColor}"
|
||||
Visibility="{x:Bind IsCustomFocused, Mode=OneWay}" />
|
||||
|
||||
<Border
|
||||
x:Name="RootContainerVisualWrapper"
|
||||
@@ -66,9 +70,9 @@
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
SenderContactPicture="{x:Bind MailItem.SenderContact.Base64ContactPicture}"
|
||||
FromAddress="{x:Bind MailItem.FromAddress, Mode=OneWay}"
|
||||
FromName="{x:Bind MailItem.FromName, Mode=OneWay}"
|
||||
SenderContactPicture="{x:Bind MailItem.SenderContact.Base64ContactPicture}"
|
||||
Visibility="{x:Bind IsAvatarVisible, Mode=OneWay}" />
|
||||
|
||||
<Grid
|
||||
@@ -145,20 +149,47 @@
|
||||
</Grid>
|
||||
|
||||
<!-- Subject + IsDraft -->
|
||||
<Grid Grid.Row="1" ColumnSpacing="4">
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<local:AnimatedIcon
|
||||
xmlns:local="using:Microsoft.UI.Xaml.Controls"
|
||||
x:Name="ExpandCollapseChevron"
|
||||
Width="14"
|
||||
Height="14"
|
||||
Margin="-4,0,2,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
local:AnimatedIcon.State="NormalOff"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Foreground="{ThemeResource ApplicationForegroundThemeBrush}"
|
||||
RenderTransformOrigin="0.5, 0.5"
|
||||
Visibility="{x:Bind IsThreadExpanderVisible, Mode=OneWay}">
|
||||
<animatedvisuals:AnimatedChevronRightDownSmallVisualSource />
|
||||
<local:AnimatedIcon.FallbackIconSource>
|
||||
<local:FontIconSource
|
||||
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||
FontSize="12"
|
||||
Glyph=""
|
||||
IsTextScaleFactorEnabled="False" />
|
||||
</local:AnimatedIcon.FallbackIconSource>
|
||||
<local:AnimatedIcon.RenderTransform />
|
||||
</local:AnimatedIcon>
|
||||
|
||||
<TextBlock
|
||||
x:Name="TitleText"
|
||||
Grid.Column="1"
|
||||
MaxLines="1"
|
||||
Text="{x:Bind MailItem.Subject}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Grid.Column="2"
|
||||
Margin="4,0,0,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="11"
|
||||
@@ -231,7 +262,7 @@
|
||||
<VisualStateGroup x:Name="SizingStates">
|
||||
<VisualState x:Name="Compact">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContainerHeight.Height" Value="50" />
|
||||
<Setter Target="RootContainer.Height" Value="60" />
|
||||
<Setter Target="ContentGrid.Padding" Value="8,0" />
|
||||
<Setter Target="PreviewTextContainer.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
@@ -243,7 +274,7 @@
|
||||
<!-- Medium -->
|
||||
<VisualState x:Name="Medium">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContainerHeight.Height" Value="65" />
|
||||
<Setter Target="RootContainer.Height" Value="80" />
|
||||
<Setter Target="ContentGrid.Padding" Value="6,0" />
|
||||
<Setter Target="PreviewTextContainer.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
@@ -255,7 +286,7 @@
|
||||
<!-- Spacious -->
|
||||
<VisualState x:Name="Spacious">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContainerHeight.Height" Value="Auto" />
|
||||
<Setter Target="RootContainer.Height" Value="Auto" />
|
||||
<Setter Target="ContentGrid.Padding" Value="12,12,6,12" />
|
||||
<Setter Target="PreviewTextContainer.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
@@ -277,6 +308,19 @@
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
|
||||
<!-- Thread Expanding States -->
|
||||
<VisualStateGroup x:Name="ExpanderStates">
|
||||
<VisualState x:Name="NotExpanded" />
|
||||
<VisualState x:Name="ExpandedState">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ExpandCollapseChevron.(controls:AnimatedIcon.State)" Value="NormalOn" />
|
||||
</VisualState.Setters>
|
||||
<VisualState.StateTriggers>
|
||||
<StateTrigger IsActive="{x:Bind IsThreadExpanded, Mode=OneWay}" />
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Numerics;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Windows.Input;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Wino.Core.Domain.Entities;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
@@ -16,12 +15,14 @@ namespace Wino.Controls
|
||||
{
|
||||
public ImagePreviewControl GetImagePreviewControl() => ContactImage;
|
||||
|
||||
public bool IsRunningHoverAction { get; set; }
|
||||
|
||||
public static readonly DependencyProperty DisplayModeProperty = DependencyProperty.Register(nameof(DisplayMode), typeof(MailListDisplayMode), typeof(MailItemDisplayInformationControl), new PropertyMetadata(MailListDisplayMode.Spacious));
|
||||
public static readonly DependencyProperty ShowPreviewTextProperty = DependencyProperty.Register(nameof(ShowPreviewText), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(true));
|
||||
public static readonly DependencyProperty IsCustomFocusedProperty = DependencyProperty.Register(nameof(IsCustomFocused), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty IsAvatarVisibleProperty = DependencyProperty.Register(nameof(IsAvatarVisible), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(true));
|
||||
public static readonly DependencyProperty IsSubjectVisibleProperty = DependencyProperty.Register(nameof(IsSubjectVisible), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(true));
|
||||
public static readonly DependencyProperty ConnectedExpanderProperty = DependencyProperty.Register(nameof(ConnectedExpander), typeof(Expander), typeof(MailItemDisplayInformationControl), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty ConnectedExpanderProperty = DependencyProperty.Register(nameof(ConnectedExpander), typeof(WinoExpander), typeof(MailItemDisplayInformationControl), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty LeftHoverActionProperty = DependencyProperty.Register(nameof(LeftHoverAction), typeof(MailOperation), typeof(MailItemDisplayInformationControl), new PropertyMetadata(MailOperation.None));
|
||||
public static readonly DependencyProperty CenterHoverActionProperty = DependencyProperty.Register(nameof(CenterHoverAction), typeof(MailOperation), typeof(MailItemDisplayInformationControl), new PropertyMetadata(MailOperation.None));
|
||||
public static readonly DependencyProperty RightHoverActionProperty = DependencyProperty.Register(nameof(RightHoverAction), typeof(MailOperation), typeof(MailItemDisplayInformationControl), new PropertyMetadata(MailOperation.None));
|
||||
@@ -29,6 +30,20 @@ namespace Wino.Controls
|
||||
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 static readonly DependencyProperty IsThreadExpanderVisibleProperty = DependencyProperty.Register(nameof(IsThreadExpanderVisible), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty IsThreadExpandedProperty = DependencyProperty.Register(nameof(IsThreadExpanded), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false));
|
||||
|
||||
public bool IsThreadExpanded
|
||||
{
|
||||
get { return (bool)GetValue(IsThreadExpandedProperty); }
|
||||
set { SetValue(IsThreadExpandedProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsThreadExpanderVisible
|
||||
{
|
||||
get { return (bool)GetValue(IsThreadExpanderVisibleProperty); }
|
||||
set { SetValue(IsThreadExpanderVisibleProperty, value); }
|
||||
}
|
||||
|
||||
public bool Prefer24HourTimeFormat
|
||||
{
|
||||
@@ -72,10 +87,9 @@ namespace Wino.Controls
|
||||
set { SetValue(RightHoverActionProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
public Expander ConnectedExpander
|
||||
public WinoExpander ConnectedExpander
|
||||
{
|
||||
get { return (Expander)GetValue(ConnectedExpanderProperty); }
|
||||
get { return (WinoExpander)GetValue(ConnectedExpanderProperty); }
|
||||
set { SetValue(ConnectedExpanderProperty, value); }
|
||||
}
|
||||
|
||||
@@ -109,8 +123,6 @@ namespace Wino.Controls
|
||||
set { SetValue(DisplayModeProperty, value); }
|
||||
}
|
||||
|
||||
private bool tappedHandlingFlag = false;
|
||||
|
||||
public MailItemDisplayInformationControl()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
@@ -147,38 +159,22 @@ namespace Wino.Controls
|
||||
|
||||
private void ExecuteHoverAction(MailOperation operation)
|
||||
{
|
||||
IsRunningHoverAction = true;
|
||||
|
||||
MailOperationPreperationRequest package = null;
|
||||
|
||||
if (MailItem is MailCopy mailCopy)
|
||||
package = new MailOperationPreperationRequest(operation, mailCopy, toggleExecution: true);
|
||||
else if (MailItem is ThreadMailItemViewModel threadMailItemViewModel)
|
||||
package = new MailOperationPreperationRequest(operation, threadMailItemViewModel.GetMailCopies(), toggleExecution: true);
|
||||
else if (MailItem is ThreadMailItem threadMailItem)
|
||||
package = new MailOperationPreperationRequest(operation, threadMailItem.ThreadItems.Cast<MailItemViewModel>().Select(a => a.MailCopy), toggleExecution: true);
|
||||
|
||||
if (package == null) return;
|
||||
|
||||
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);
|
||||
|
||||
@@ -1,17 +1,129 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using CommunityToolkit.Diagnostics;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Hosting;
|
||||
using Windows.UI.Xaml.Markup;
|
||||
|
||||
namespace Wino.Controls
|
||||
{
|
||||
public class WinoExpander : Expander
|
||||
[ContentProperty(Name = nameof(Content))]
|
||||
public class WinoExpander : Control
|
||||
{
|
||||
private const string PART_HeaderGrid = "HeaderGrid";
|
||||
private const string PART_ContentAreaWrapper = "ContentAreaWrapper";
|
||||
private const string PART_ContentArea = "ContentArea";
|
||||
|
||||
private ContentControl HeaderGrid;
|
||||
private ContentControl ContentArea;
|
||||
private Grid ContentAreaWrapper;
|
||||
|
||||
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(nameof(Header), typeof(UIElement), typeof(WinoExpander), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(nameof(Content), typeof(UIElement), typeof(WinoExpander), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register(nameof(IsExpanded), typeof(bool), typeof(WinoExpander), new PropertyMetadata(false, new PropertyChangedCallback(OnIsExpandedChanged)));
|
||||
public static readonly DependencyProperty TemplateSettingsProperty = DependencyProperty.Register(nameof(TemplateSettings), typeof(WinoExpanderTemplateSettings), typeof(WinoExpander), new PropertyMetadata(new WinoExpanderTemplateSettings()));
|
||||
|
||||
public UIElement Content
|
||||
{
|
||||
get { return (UIElement)GetValue(ContentProperty); }
|
||||
set { SetValue(ContentProperty, value); }
|
||||
}
|
||||
|
||||
public WinoExpanderTemplateSettings TemplateSettings
|
||||
{
|
||||
get { return (WinoExpanderTemplateSettings)GetValue(TemplateSettingsProperty); }
|
||||
set { SetValue(TemplateSettingsProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsExpanded
|
||||
{
|
||||
get { return (bool)GetValue(IsExpandedProperty); }
|
||||
set { SetValue(IsExpandedProperty, value); }
|
||||
}
|
||||
|
||||
public UIElement Header
|
||||
{
|
||||
get { return (UIElement)GetValue(HeaderProperty); }
|
||||
set { SetValue(HeaderProperty, value); }
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
if (GetTemplateChild("ExpanderHeader") is ToggleButton toggleButton)
|
||||
|
||||
HeaderGrid = GetTemplateChild(PART_HeaderGrid) as ContentControl;
|
||||
ContentAreaWrapper = GetTemplateChild(PART_ContentAreaWrapper) as Grid;
|
||||
ContentArea = GetTemplateChild(PART_ContentArea) as ContentControl;
|
||||
|
||||
Guard.IsNotNull(HeaderGrid, nameof(HeaderGrid));
|
||||
Guard.IsNotNull(ContentAreaWrapper, nameof(ContentAreaWrapper));
|
||||
Guard.IsNotNull(ContentArea, nameof(ContentArea));
|
||||
|
||||
var clipComposition = ElementCompositionPreview.GetElementVisual(ContentAreaWrapper);
|
||||
clipComposition.Clip = clipComposition.Compositor.CreateInsetClip();
|
||||
|
||||
ContentAreaWrapper.SizeChanged += ContentSizeChanged;
|
||||
HeaderGrid.Tapped += HeaderTapped;
|
||||
}
|
||||
|
||||
private void ContentSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
TemplateSettings.ContentHeight = e.NewSize.Height;
|
||||
TemplateSettings.NegativeContentHeight = -1 * (double)e.NewSize.Height;
|
||||
}
|
||||
|
||||
private void HeaderTapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
|
||||
{
|
||||
// Tapped is delegated from executing hover action like flag or delete.
|
||||
// No need to toggle the expander.
|
||||
|
||||
if (Header is MailItemDisplayInformationControl itemDisplayInformationControl &&
|
||||
itemDisplayInformationControl.IsRunningHoverAction)
|
||||
{
|
||||
toggleButton.Padding = new Windows.UI.Xaml.Thickness(0, 4, 0, 4);
|
||||
itemDisplayInformationControl.IsRunningHoverAction = false;
|
||||
return;
|
||||
}
|
||||
|
||||
IsExpanded = !IsExpanded;
|
||||
}
|
||||
|
||||
private static void OnIsExpandedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (obj is WinoExpander control)
|
||||
control.UpdateVisualStates();
|
||||
}
|
||||
|
||||
private void UpdateVisualStates()
|
||||
{
|
||||
VisualStateManager.GoToState(this, IsExpanded ? "Expanded" : "Collapsed", true);
|
||||
}
|
||||
}
|
||||
|
||||
#region Settings
|
||||
|
||||
public class WinoExpanderTemplateSettings : DependencyObject
|
||||
{
|
||||
public static readonly DependencyProperty HeaderHeightProperty = DependencyProperty.Register(nameof(HeaderHeight), typeof(double), typeof(WinoExpanderTemplateSettings), new PropertyMetadata(0.0));
|
||||
public static readonly DependencyProperty ContentHeightProperty = DependencyProperty.Register(nameof(ContentHeight), typeof(double), typeof(WinoExpanderTemplateSettings), new PropertyMetadata(0.0));
|
||||
public static readonly DependencyProperty NegativeContentHeightProperty = DependencyProperty.Register(nameof(NegativeContentHeight), typeof(double), typeof(WinoExpanderTemplateSettings), new PropertyMetadata(0.0));
|
||||
|
||||
public double NegativeContentHeight
|
||||
{
|
||||
get { return (double)GetValue(NegativeContentHeightProperty); }
|
||||
set { SetValue(NegativeContentHeightProperty, value); }
|
||||
}
|
||||
|
||||
public double HeaderHeight
|
||||
{
|
||||
get { return (double)GetValue(HeaderHeightProperty); }
|
||||
set { SetValue(HeaderHeightProperty, value); }
|
||||
}
|
||||
|
||||
public double ContentHeight
|
||||
{
|
||||
get { return (double)GetValue(ContentHeightProperty); }
|
||||
set { SetValue(ContentHeightProperty, value); }
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,7 +93,8 @@ namespace Wino.Extensions
|
||||
|
||||
if (isVerticalScrolling)
|
||||
{
|
||||
scrollViewer.ChangeView(null, position.Y, zoomFactor, !smoothScrolling);
|
||||
// Accomodate for additional header.
|
||||
scrollViewer.ChangeView(null, Math.Max(0, position.Y - 48), zoomFactor, !smoothScrolling);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
89
Wino.Mail/Styles/WinoExpanderStyle.xaml
Normal file
89
Wino.Mail/Styles/WinoExpanderStyle.xaml
Normal file
@@ -0,0 +1,89 @@
|
||||
<ResourceDictionary
|
||||
x:Class="Wino.Styles.WinoExpanderStyle"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals"
|
||||
xmlns:controls="using:Wino.Controls"
|
||||
xmlns:local="using:Wino.Styles"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls">
|
||||
|
||||
<ControlTemplate x:Key="DefaultWinoThreadControlTemplate" TargetType="controls:WinoExpander">
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header -->
|
||||
<ContentControl
|
||||
x:Name="HeaderGrid"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
Background="{TemplateBinding Background}"
|
||||
Content="{TemplateBinding Header}" />
|
||||
|
||||
<!-- Content -->
|
||||
<Grid x:Name="ContentAreaWrapper" Grid.Row="1">
|
||||
<ContentControl
|
||||
x:Name="ContentArea"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
Content="{TemplateBinding Content}"
|
||||
RenderTransformOrigin="0.5,0.5"
|
||||
Visibility="Collapsed">
|
||||
<ContentControl.RenderTransform>
|
||||
<CompositeTransform />
|
||||
</ContentControl.RenderTransform>
|
||||
</ContentControl>
|
||||
</Grid>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="OpenCloseStates">
|
||||
<VisualState x:Name="Collapsed">
|
||||
<VisualState.Storyboard>
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentArea" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0:0:0.111" Value="Collapsed" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ContentArea" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0" Value="0" />
|
||||
<SplineDoubleKeyFrame
|
||||
KeySpline="1.0, 1.0, 0.0, 1.0"
|
||||
KeyTime="0:0:0.111"
|
||||
Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.NegativeContentHeight}" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState.Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Expanded">
|
||||
<VisualState.Storyboard>
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentArea" Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ContentArea" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.NegativeContentHeight}" />
|
||||
<SplineDoubleKeyFrame
|
||||
KeySpline="0.0, 0.0, 0.0, 1.0"
|
||||
KeyTime="0:0:0.333"
|
||||
Value="0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState.Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style TargetType="controls:WinoExpander">
|
||||
<Setter Property="Background" Value="{ThemeResource AppBarItemBackgroundThemeBrush}" />
|
||||
<Setter Property="Template" Value="{StaticResource DefaultWinoThreadControlTemplate}" />
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
12
Wino.Mail/Styles/WinoExpanderStyle.xaml.cs
Normal file
12
Wino.Mail/Styles/WinoExpanderStyle.xaml.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Windows.UI.Xaml;
|
||||
|
||||
namespace Wino.Styles
|
||||
{
|
||||
partial class WinoExpanderStyle : ResourceDictionary
|
||||
{
|
||||
public WinoExpanderStyle()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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">
|
||||
@@ -158,18 +169,14 @@
|
||||
<DataTemplate x:DataType="viewModelData:ThreadMailItemViewModel">
|
||||
<controls:WinoExpander
|
||||
x:Name="ThreadExpander"
|
||||
Padding="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
BackgroundSizing="InnerBorderEdge"
|
||||
BorderThickness="0"
|
||||
IsExpanded="{x:Bind IsThreadExpanded, Mode=TwoWay}">
|
||||
<muxc:Expander.Header>
|
||||
<controls:WinoExpander.Header>
|
||||
<controls:MailItemDisplayInformationControl
|
||||
x:DefaultBindMode="OneWay"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
CanDrag="True"
|
||||
CenterHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.CenterHoverAction, Mode=OneWay}"
|
||||
ConnectedExpander="{Binding ElementName=ThreadExpander}"
|
||||
ContextRequested="MailItemContextRequested"
|
||||
@@ -180,13 +187,15 @@
|
||||
IsAvatarVisible="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsShowSenderPicturesEnabled, Mode=OneWay}"
|
||||
IsHitTestVisible="True"
|
||||
IsHoverActionsEnabled="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsHoverActionsEnabled, Mode=OneWay}"
|
||||
IsThreadExpanded="{x:Bind IsThreadExpanded, Mode=TwoWay}"
|
||||
IsThreadExpanderVisible="True"
|
||||
LeftHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.LeftHoverAction, Mode=OneWay}"
|
||||
MailItem="{x:Bind MailItem, Mode=OneWay}"
|
||||
Prefer24HourTimeFormat="{Binding ElementName=root, Path=ViewModel.PreferencesService.Prefer24HourTimeFormat, Mode=OneWay}"
|
||||
RightHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.RightHoverAction, Mode=OneWay}"
|
||||
ShowPreviewText="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsShowPreviewEnabled, Mode=OneWay}" />
|
||||
</muxc:Expander.Header>
|
||||
<muxc:Expander.Content>
|
||||
</controls:WinoExpander.Header>
|
||||
<controls:WinoExpander.Content>
|
||||
<listview:WinoListView
|
||||
x:Name="ThreadItemsList"
|
||||
ui:ListViewExtensions.ItemContainerStretchDirection="Horizontal"
|
||||
@@ -201,35 +210,13 @@
|
||||
</TransitionCollection>
|
||||
</ListView.ItemContainerTransitions>
|
||||
</listview:WinoListView>
|
||||
</muxc:Expander.Content>
|
||||
</controls:WinoExpander.Content>
|
||||
</controls:WinoExpander>
|
||||
</DataTemplate>
|
||||
</selectors:MailItemDisplaySelector.ThreadMailItemTemplate>
|
||||
</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 +259,8 @@
|
||||
<Border
|
||||
x:Name="MailListContainer"
|
||||
Grid.Column="0"
|
||||
Padding="5,0,0,0"
|
||||
Padding="5,5,5,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="{ThemeResource WinoContentZoneBackgroud}"
|
||||
BorderBrush="{StaticResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
@@ -284,209 +272,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="" />
|
||||
</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="" />
|
||||
</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 +394,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 -->
|
||||
@@ -570,11 +462,12 @@
|
||||
<SemanticZoom.ZoomedInView>
|
||||
<listview:WinoListView
|
||||
x:Name="MailListView"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
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"
|
||||
|
||||
@@ -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
@@ -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" />
|
||||
@@ -312,6 +311,9 @@
|
||||
<Compile Include="Styles\CustomMessageDialogStyles.xaml.cs">
|
||||
<DependentUpon>CustomMessageDialogStyles.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Styles\WinoExpanderStyle.xaml.cs">
|
||||
<DependentUpon>WinoExpanderStyle.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\Abstract\AboutPageAbstract.cs" />
|
||||
<Compile Include="Views\Abstract\AccountDetailsPageAbstract.cs" />
|
||||
<Compile Include="Views\Abstract\AccountManagementPageAbstract.cs" />
|
||||
@@ -456,10 +458,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>
|
||||
@@ -532,6 +530,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Styles\WinoExpanderStyle.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Styles\WinoInfoBar.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
<Identity
|
||||
Name="58272BurakKSE.WinoMailPreview"
|
||||
Publisher="CN=51FBDAF3-E212-4149-89A2-A2636B3BC911"
|
||||
Version="1.8.4.0" />
|
||||
Version="1.8.5.0" />
|
||||
|
||||
<Extensions>
|
||||
<!-- Publisher Cache Folders -->
|
||||
|
||||
Reference in New Issue
Block a user