Render mail categories in list items
This commit is contained in:
@@ -172,6 +172,9 @@ public class MailCopy
|
||||
[Ignore]
|
||||
public Guid? ReadReceiptMessageUniqueId { get; set; }
|
||||
|
||||
[Ignore]
|
||||
public List<MailCategory> Categories { get; set; } = [];
|
||||
|
||||
public IEnumerable<Guid> GetContainingIds() => [UniqueId];
|
||||
public override string ToString() => $"{Subject} <-> {Id}";
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ public enum MailCopyChangeFlags
|
||||
SenderContact = 1 << 23,
|
||||
UniqueId = 1 << 24,
|
||||
ReadReceiptState = 1 << 25,
|
||||
Categories = 1 << 26,
|
||||
All = Id |
|
||||
FolderId |
|
||||
ThreadId |
|
||||
@@ -57,5 +58,6 @@ public enum MailCopyChangeFlags
|
||||
AssignedAccount |
|
||||
SenderContact |
|
||||
UniqueId |
|
||||
ReadReceiptState
|
||||
ReadReceiptState |
|
||||
Categories
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ public interface IMailCategoryService
|
||||
Task AssignCategoryAsync(Guid categoryId, IEnumerable<Guid> mailCopyUniqueIds);
|
||||
Task UnassignCategoryAsync(Guid categoryId, IEnumerable<Guid> mailCopyUniqueIds);
|
||||
Task<List<MailCategory>> GetCategoriesForMailAsync(Guid accountId, IEnumerable<Guid> mailCopyUniqueIds);
|
||||
Task<IReadOnlyDictionary<Guid, IReadOnlyList<MailCategory>>> GetCategoriesByMailAsync(Guid accountId, IEnumerable<Guid> mailCopyUniqueIds);
|
||||
Task<List<Guid>> GetAssignedCategoryIdsForAllAsync(IEnumerable<Guid> mailCopyUniqueIds);
|
||||
Task<List<string>> GetCategoryNamesForMailAsync(Guid mailCopyUniqueId);
|
||||
Task<List<MailCopy>> GetMailCopiesForCategoryAsync(Guid categoryId);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
|
||||
namespace Wino.Core.Domain.Interfaces;
|
||||
@@ -27,4 +29,6 @@ public interface IMailItemDisplayInformation : INotifyPropertyChanged
|
||||
bool HasReadReceiptTracking { get; }
|
||||
bool IsReadReceiptAcknowledged { get; }
|
||||
string ReadReceiptDisplayText { get; }
|
||||
IReadOnlyList<MailCategory> Categories { get; }
|
||||
bool HasCategories { get; }
|
||||
}
|
||||
|
||||
@@ -389,6 +389,24 @@ public partial class PersonalizationPageViewModel : CoreBaseViewModel
|
||||
public bool HasReadReceiptTracking { get; } = false;
|
||||
public bool IsReadReceiptAcknowledged { get; } = false;
|
||||
public string ReadReceiptDisplayText { get; } = string.Empty;
|
||||
public IReadOnlyList<MailCategory> Categories { get; } =
|
||||
[
|
||||
new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Name = "Follow Up",
|
||||
BackgroundColorHex = "#DCEBFF",
|
||||
TextColorHex = "#0B5CAD"
|
||||
},
|
||||
new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Name = "Planning",
|
||||
BackgroundColorHex = "#DDF5D7",
|
||||
TextColorHex = "#236A1E"
|
||||
}
|
||||
];
|
||||
public bool HasCategories => Categories.Count > 0;
|
||||
public AccountContact SenderContact { get; } = null;
|
||||
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
|
||||
{
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
|
||||
@@ -71,6 +73,8 @@ public partial class AccountContactViewModel : ObservableObject, IMailItemDispla
|
||||
public bool HasReadReceiptTracking => false;
|
||||
public bool IsReadReceiptAcknowledged => false;
|
||||
public string ReadReceiptDisplayText => string.Empty;
|
||||
public IReadOnlyList<MailCategory> Categories => [];
|
||||
public bool HasCategories => false;
|
||||
public AccountContact SenderContact => new()
|
||||
{
|
||||
Address = Address,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
@@ -39,6 +40,8 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient,
|
||||
[NotifyPropertyChangedFor(nameof(UniqueId))]
|
||||
[NotifyPropertyChangedFor(nameof(ContactPictureFileId))]
|
||||
[NotifyPropertyChangedFor(nameof(SenderContact))]
|
||||
[NotifyPropertyChangedFor(nameof(Categories))]
|
||||
[NotifyPropertyChangedFor(nameof(HasCategories))]
|
||||
public partial MailCopy MailCopy { get; set; } = mailCopy;
|
||||
|
||||
[ObservableProperty]
|
||||
@@ -124,6 +127,10 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient,
|
||||
_ => string.Empty
|
||||
};
|
||||
|
||||
public IReadOnlyList<MailCategory> Categories => MailCopy.Categories;
|
||||
|
||||
public bool HasCategories => Categories.Count > 0;
|
||||
|
||||
public string DraftId
|
||||
{
|
||||
get => MailCopy.DraftId;
|
||||
@@ -262,6 +269,7 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient,
|
||||
nameof(FolderId) => MailCopyChangeFlags.FolderId,
|
||||
nameof(UniqueId) => MailCopyChangeFlags.UniqueId,
|
||||
nameof(ContactPictureFileId) or nameof(SenderContact) => MailCopyChangeFlags.SenderContact,
|
||||
nameof(Categories) or nameof(HasCategories) => MailCopyChangeFlags.Categories,
|
||||
_ => MailCopyChangeFlags.None
|
||||
};
|
||||
}
|
||||
@@ -474,9 +482,21 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient,
|
||||
Queue(nameof(SenderContact));
|
||||
}
|
||||
|
||||
if ((changedFlags & MailCopyChangeFlags.Categories) != 0)
|
||||
{
|
||||
Queue(nameof(Categories));
|
||||
Queue(nameof(HasCategories));
|
||||
}
|
||||
|
||||
foreach (var changedProperty in changedProperties)
|
||||
{
|
||||
OnPropertyChanged(changedProperty);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateCategories(IReadOnlyList<MailCategory> categories)
|
||||
{
|
||||
MailCopy.Categories = categories?.ToList() ?? [];
|
||||
RaisePropertyChanges(MailCopyChangeFlags.Categories);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
@@ -111,6 +112,13 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IMailListIte
|
||||
public bool IsReadReceiptAcknowledged => newestMailViewModel?.IsReadReceiptAcknowledged ?? false;
|
||||
|
||||
public string ReadReceiptDisplayText => newestMailViewModel?.ReadReceiptDisplayText ?? string.Empty;
|
||||
public IReadOnlyList<MailCategory> Categories => ThreadEmails
|
||||
.SelectMany(a => a.Categories)
|
||||
.GroupBy(a => a.Id)
|
||||
.Select(a => a.First())
|
||||
.OrderBy(a => a.Name)
|
||||
.ToList();
|
||||
public bool HasCategories => ThreadEmails.Any(a => a.HasCategories);
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether any email in this thread is a draft
|
||||
@@ -206,6 +214,8 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IMailListIte
|
||||
[NotifyPropertyChangedFor(nameof(UniqueId))]
|
||||
[NotifyPropertyChangedFor(nameof(ContactPictureFileId))]
|
||||
[NotifyPropertyChangedFor(nameof(SenderContact))]
|
||||
[NotifyPropertyChangedFor(nameof(Categories))]
|
||||
[NotifyPropertyChangedFor(nameof(HasCategories))]
|
||||
public partial ObservableCollection<MailItemViewModel> ThreadEmails { get; set; } = [];
|
||||
|
||||
private MailItemViewModel newestMailViewModel => _cachedNewestMailViewModel;
|
||||
@@ -467,6 +477,12 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IMailListIte
|
||||
Queue(nameof(ContactPictureFileId));
|
||||
Queue(nameof(SenderContact));
|
||||
}
|
||||
|
||||
if ((changedFlags & MailCopyChangeFlags.Categories) != 0)
|
||||
{
|
||||
Queue(nameof(Categories));
|
||||
Queue(nameof(HasCategories));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,6 +511,12 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IMailListIte
|
||||
if ((changedFlags & MailCopyChangeFlags.IsDraft) != 0 || changedFlags == MailCopyChangeFlags.All)
|
||||
Queue(nameof(IsDraft));
|
||||
|
||||
if ((changedFlags & MailCopyChangeFlags.Categories) != 0 || changedFlags == MailCopyChangeFlags.All)
|
||||
{
|
||||
Queue(nameof(Categories));
|
||||
Queue(nameof(HasCategories));
|
||||
}
|
||||
|
||||
foreach (var changedProperty in changedProperties)
|
||||
{
|
||||
OnPropertyChanged(changedProperty);
|
||||
|
||||
@@ -1329,6 +1329,8 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
||||
|
||||
private async Task<List<MailItemViewModel>> PrepareMailViewModelsAsync(IEnumerable<MailCopy> mailItems, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await PopulateMailCategoriesAsync(mailItems, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Run ViewModel creation on background thread to avoid blocking UI
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
@@ -1342,6 +1344,38 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task PopulateMailCategoriesAsync(IEnumerable<MailCopy> mailItems, CancellationToken cancellationToken)
|
||||
{
|
||||
var mails = mailItems?.Where(a => a != null).ToList() ?? [];
|
||||
if (mails.Count == 0)
|
||||
return;
|
||||
|
||||
var accountIdsByFolderId = ActiveFolder?.HandlingFolders?
|
||||
.GroupBy(a => a.Id)
|
||||
.ToDictionary(a => a.Key, a => a.First().MailAccountId) ?? new Dictionary<Guid, Guid>();
|
||||
|
||||
var mailsByAccount = mails
|
||||
.GroupBy(mail => ResolveMailAccountId(mail, accountIdsByFolderId))
|
||||
.Where(group => group.Key != Guid.Empty)
|
||||
.ToList();
|
||||
|
||||
foreach (var groupedMails in mailsByAccount)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var categoriesByMail = await _mailCategoryService
|
||||
.GetCategoriesByMailAsync(groupedMails.Key, groupedMails.Select(a => a.UniqueId))
|
||||
.ConfigureAwait(false);
|
||||
|
||||
foreach (var mail in groupedMails)
|
||||
{
|
||||
mail.Categories = categoriesByMail.TryGetValue(mail.UniqueId, out var categories)
|
||||
? categories.ToList()
|
||||
: [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<HashSet<Guid>> GetPendingOperationUniqueIdsForActiveFolderAccountsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var pendingOperationUniqueIds = new HashSet<Guid>();
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
@@ -187,6 +188,24 @@ public partial class MessageListPageViewModel : MailBaseViewModel
|
||||
public bool HasReadReceiptTracking => true;
|
||||
public bool IsReadReceiptAcknowledged => false;
|
||||
public string ReadReceiptDisplayText => Translator.MailReceiptStatus_Requested;
|
||||
public IReadOnlyList<MailCategory> Categories =>
|
||||
[
|
||||
new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Name = "Urgent",
|
||||
BackgroundColorHex = "#FFE1DE",
|
||||
TextColorHex = "#A1260D"
|
||||
},
|
||||
new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Name = "Client",
|
||||
BackgroundColorHex = "#E4E8FF",
|
||||
TextColorHex = "#4255C5"
|
||||
}
|
||||
];
|
||||
public bool HasCategories => Categories.Count > 0;
|
||||
public AccountContact SenderContact => new()
|
||||
{
|
||||
Address = "hi@bkaan.dev",
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
xmlns:enums="using:Wino.Core.Domain.Enums"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
xmlns:mail="using:Wino.Core.Domain.Entities.Mail"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
@@ -23,6 +24,28 @@
|
||||
Unloaded="OnUnloaded">
|
||||
|
||||
<UserControl.Resources>
|
||||
<DataTemplate x:Key="DetailedMailCategoryTemplate" x:DataType="mail:MailCategory">
|
||||
<Border
|
||||
Margin="0,0,4,0"
|
||||
Padding="6,2"
|
||||
Background="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(BackgroundColorHex), Mode=OneWay}"
|
||||
CornerRadius="8">
|
||||
<TextBlock
|
||||
Foreground="{x:Bind helpers:XamlHelpers.GetCategoryTextBrush(TextColorHex, BackgroundColorHex), Mode=OneWay}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind Name, Mode=OneWay}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="CompactMailCategoryTemplate" x:DataType="mail:MailCategory">
|
||||
<Ellipse
|
||||
Width="8"
|
||||
Height="8"
|
||||
Margin="0,0,4,0"
|
||||
Fill="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(BackgroundColorHex), Mode=OneWay}" />
|
||||
</DataTemplate>
|
||||
|
||||
<Style
|
||||
x:Key="HoverActionButtonStyle"
|
||||
BasedOn="{StaticResource DefaultButtonStyle}"
|
||||
@@ -89,6 +112,7 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Sender + IsDraft + Hover Buttons -->
|
||||
@@ -206,6 +230,21 @@
|
||||
Text="{x:Bind helpers:XamlHelpers.GetMailItemDisplaySummaryForListing(MailItemInformation.IsDraft, MailItemInformation.CreationDate, Prefer24HourTimeFormat), Mode=OneWay}" />
|
||||
</Grid>
|
||||
|
||||
<ItemsControl
|
||||
x:Name="DetailedCategoriesContainer"
|
||||
Grid.Row="3"
|
||||
Margin="0,4,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
ItemTemplate="{StaticResource DetailedMailCategoryTemplate}"
|
||||
ItemsSource="{x:Bind MailItemInformation.Categories, Mode=OneWay}"
|
||||
Visibility="{x:Bind helpers:XamlHelpers.CountToVisibilityConverter(MailItemInformation.Categories.Count), Mode=OneWay}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
|
||||
<!-- Message -->
|
||||
<Grid
|
||||
x:Name="PreviewTextContainerRoot"
|
||||
@@ -233,6 +272,18 @@
|
||||
Margin="4,4,1,4"
|
||||
Orientation="Horizontal"
|
||||
Spacing="2">
|
||||
<ItemsControl
|
||||
x:Name="CompactCategoriesContainer"
|
||||
VerticalAlignment="Center"
|
||||
ItemTemplate="{StaticResource CompactMailCategoryTemplate}"
|
||||
ItemsSource="{x:Bind MailItemInformation.Categories, Mode=OneWay}"
|
||||
Visibility="Collapsed">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
|
||||
<TextBlock
|
||||
Margin="0,0,4,0"
|
||||
@@ -288,8 +339,13 @@
|
||||
<VisualStateGroup x:Name="SizingStates">
|
||||
<VisualState x:Name="Compact">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="RootContainer.Height" Value="60" />
|
||||
<Setter Target="ContentGrid.Padding" Value="8,0" />
|
||||
<Setter Target="RootContainer.Height" Value="64" />
|
||||
<Setter Target="ContentGrid.Padding" Value="8,6,8,6" />
|
||||
<Setter Target="ContentStackpanel.VerticalAlignment" Value="Center" />
|
||||
<Setter Target="PreviewTextContainerRoot.Margin" Value="0" />
|
||||
<Setter Target="IconsContainer.Margin" Value="4,0,1,0" />
|
||||
<Setter Target="DetailedCategoriesContainer.Visibility" Value="Collapsed" />
|
||||
<Setter Target="CompactCategoriesContainer.Visibility" Value="Visible" />
|
||||
<Setter Target="PreviewTextContainer.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
<VisualState.StateTriggers>
|
||||
@@ -300,8 +356,13 @@
|
||||
<!-- Medium -->
|
||||
<VisualState x:Name="Medium">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="RootContainer.Height" Value="80" />
|
||||
<Setter Target="ContentGrid.Padding" Value="6,0" />
|
||||
<Setter Target="RootContainer.Height" Value="96" />
|
||||
<Setter Target="ContentGrid.Padding" Value="6,8,6,6" />
|
||||
<Setter Target="ContentStackpanel.VerticalAlignment" Value="Top" />
|
||||
<Setter Target="DetailedCategoriesContainer.Margin" Value="0,2,0,0" />
|
||||
<Setter Target="PreviewTextContainerRoot.Margin" Value="0,2,0,0" />
|
||||
<Setter Target="IconsContainer.Margin" Value="4,2,1,0" />
|
||||
<Setter Target="CompactCategoriesContainer.Visibility" Value="Collapsed" />
|
||||
<Setter Target="PreviewTextContainer.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
<VisualState.StateTriggers>
|
||||
@@ -314,6 +375,11 @@
|
||||
<VisualState.Setters>
|
||||
<Setter Target="RootContainer.Height" Value="Auto" />
|
||||
<Setter Target="ContentGrid.Padding" Value="12,12,6,12" />
|
||||
<Setter Target="ContentStackpanel.VerticalAlignment" Value="Center" />
|
||||
<Setter Target="DetailedCategoriesContainer.Margin" Value="0,4,0,0" />
|
||||
<Setter Target="PreviewTextContainerRoot.Margin" Value="0" />
|
||||
<Setter Target="IconsContainer.Margin" Value="4,4,1,4" />
|
||||
<Setter Target="CompactCategoriesContainer.Visibility" Value="Collapsed" />
|
||||
<Setter Target="PreviewTextContainer.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
<VisualState.StateTriggers>
|
||||
|
||||
@@ -152,6 +152,12 @@ public static class XamlHelpers
|
||||
public static Color GetWindowsColorFromHex(string hex) => hex.ToColor();
|
||||
|
||||
public static SolidColorBrush GetSolidColorBrushFromHex(string colorHex) => string.IsNullOrEmpty(colorHex) ? new SolidColorBrush(Colors.Transparent) : new SolidColorBrush(colorHex.ToColor());
|
||||
public static SolidColorBrush GetCategoryTextBrush(string textColorHex, string backgroundColorHex)
|
||||
=> !string.IsNullOrWhiteSpace(textColorHex)
|
||||
? GetSolidColorBrushFromHex(textColorHex)
|
||||
: string.IsNullOrWhiteSpace(backgroundColorHex)
|
||||
? new SolidColorBrush(Colors.Black)
|
||||
: GetReadableTextColor(backgroundColorHex);
|
||||
public static FontWeight GetFontWeightBySyncState(bool isSyncing) => isSyncing ? FontWeights.SemiBold : FontWeights.Normal;
|
||||
|
||||
public static Brush GetWizardStepBadgeBrush(bool isActive)
|
||||
|
||||
@@ -288,6 +288,39 @@ public class MailCategoryService : BaseDatabaseService, IMailCategoryService
|
||||
[accountId, .. uniqueIds.Cast<object>()]).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyDictionary<Guid, IReadOnlyList<MailCategory>>> GetCategoriesByMailAsync(Guid accountId, IEnumerable<Guid> mailCopyUniqueIds)
|
||||
{
|
||||
var uniqueIds = mailCopyUniqueIds?.Distinct().ToList() ?? [];
|
||||
if (uniqueIds.Count == 0)
|
||||
return new Dictionary<Guid, IReadOnlyList<MailCategory>>();
|
||||
|
||||
var placeholders = string.Join(",", uniqueIds.Select(_ => "?"));
|
||||
var sql =
|
||||
$"SELECT {nameof(MailCategoryAssignment)}.{nameof(MailCategoryAssignment.MailCopyUniqueId)} as {nameof(MailCategoryRow.MailCopyUniqueId)}, " +
|
||||
$"{nameof(MailCategory)}.{nameof(MailCategory.Id)} as {nameof(MailCategoryRow.Id)}, " +
|
||||
$"{nameof(MailCategory)}.{nameof(MailCategory.MailAccountId)} as {nameof(MailCategoryRow.MailAccountId)}, " +
|
||||
$"{nameof(MailCategory)}.{nameof(MailCategory.RemoteId)} as {nameof(MailCategoryRow.RemoteId)}, " +
|
||||
$"{nameof(MailCategory)}.{nameof(MailCategory.Name)} as {nameof(MailCategoryRow.Name)}, " +
|
||||
$"{nameof(MailCategory)}.{nameof(MailCategory.IsFavorite)} as {nameof(MailCategoryRow.IsFavorite)}, " +
|
||||
$"{nameof(MailCategory)}.{nameof(MailCategory.BackgroundColorHex)} as {nameof(MailCategoryRow.BackgroundColorHex)}, " +
|
||||
$"{nameof(MailCategory)}.{nameof(MailCategory.TextColorHex)} as {nameof(MailCategoryRow.TextColorHex)}, " +
|
||||
$"{nameof(MailCategory)}.{nameof(MailCategory.Source)} as {nameof(MailCategoryRow.Source)} " +
|
||||
$"FROM {nameof(MailCategory)} " +
|
||||
$"INNER JOIN {nameof(MailCategoryAssignment)} ON {nameof(MailCategory)}.{nameof(MailCategory.Id)} = {nameof(MailCategoryAssignment)}.{nameof(MailCategoryAssignment.MailCategoryId)} " +
|
||||
$"WHERE {nameof(MailCategory)}.{nameof(MailCategory.MailAccountId)} = ? AND {nameof(MailCategoryAssignment)}.{nameof(MailCategoryAssignment.MailCopyUniqueId)} IN ({placeholders}) " +
|
||||
$"ORDER BY {nameof(MailCategoryAssignment)}.{nameof(MailCategoryAssignment.MailCopyUniqueId)}, {nameof(MailCategory)}.{nameof(MailCategory.Name)} COLLATE NOCASE";
|
||||
|
||||
var rows = await Connection.QueryAsync<MailCategoryRow>(
|
||||
sql,
|
||||
[accountId, .. uniqueIds.Cast<object>()]).ConfigureAwait(false);
|
||||
|
||||
return rows
|
||||
.GroupBy(a => a.MailCopyUniqueId)
|
||||
.ToDictionary(
|
||||
a => a.Key,
|
||||
a => (IReadOnlyList<MailCategory>)a.Select(static row => row.ToMailCategory()).ToList());
|
||||
}
|
||||
|
||||
public async Task<List<Guid>> GetAssignedCategoryIdsForAllAsync(IEnumerable<Guid> mailCopyUniqueIds)
|
||||
{
|
||||
var uniqueIds = mailCopyUniqueIds?.Distinct().ToList() ?? [];
|
||||
@@ -355,4 +388,21 @@ public class MailCategoryService : BaseDatabaseService, IMailCategoryService
|
||||
|
||||
private static string NormalizeCategoryName(string name)
|
||||
=> name?.Trim() ?? string.Empty;
|
||||
|
||||
private sealed class MailCategoryRow : MailCategory
|
||||
{
|
||||
public Guid MailCopyUniqueId { get; set; }
|
||||
|
||||
public MailCategory ToMailCategory() => new()
|
||||
{
|
||||
Id = Id,
|
||||
MailAccountId = MailAccountId,
|
||||
RemoteId = RemoteId,
|
||||
Name = Name,
|
||||
IsFavorite = IsFavorite,
|
||||
BackgroundColorHex = BackgroundColorHex,
|
||||
TextColorHex = TextColorHex,
|
||||
Source = Source
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user