maksit-postclient/src/MaksIT.PostClient.UI/ViewModels/RowViewModels.cs

335 lines
9.8 KiB
C#

using System.Collections.ObjectModel;
using Avalonia;
using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel;
using MaksIT.PostClient.Client;
using MaksIT.PostClient.Shared;
namespace MaksIT.PostClient.UI.ViewModels;
public sealed class ChoiceRow {
public required string Id { get; init; }
public required string Title { get; init; }
public override string ToString() =>
Title;
public static IReadOnlyList<ChoiceRow> IncomingProtocols { get; } = [
new() { Id = MailProtocol.Imap, Title = "IMAP" },
new() { Id = MailProtocol.Pop3, Title = "POP3" }
];
public static IReadOnlyList<ChoiceRow> SecurityModes =>
[
new() { Id = MailSecurity.Auto, Title = UiLocale.Copy.SecurityAuto },
new() { Id = MailSecurity.Ssl, Title = "SSL/TLS" },
new() { Id = MailSecurity.StartTls, Title = "STARTTLS" },
new() { Id = MailSecurity.StartTlsWhenAvailable, Title = UiLocale.Copy.SecurityStartTlsIfAvailable },
new() { Id = MailSecurity.None, Title = UiLocale.Copy.SecurityNone }
];
public static IReadOnlyList<ChoiceRow> Providers { get; } = [
new() { Id = MailProvider.Imap, Title = "IMAP / POP3" },
new() { Id = MailProvider.Gmail, Title = "Gmail" },
new() { Id = MailProvider.Outlook, Title = "Outlook / Microsoft 365" },
new() { Id = MailProvider.Aruba, Title = "IT PEC — Aruba" },
new() { Id = MailProvider.Legalmail, Title = "IT PEC — InfoCert Legalmail" },
new() { Id = MailProvider.Namirial, Title = "IT/EU PEC — Namirial" },
new() { Id = MailProvider.Postecert, Title = "IT PEC — Poste Italiane" },
new() { Id = MailProvider.Register, Title = "IT PEC — Register.it" },
new() { Id = MailProvider.Libero, Title = "IT PEC — Libero" },
new() { Id = MailProvider.Intesi, Title = "EU — Intesi Group" }
];
public static ChoiceRow Incoming(string? id) =>
IncomingProtocols.FirstOrDefault(p => p.Id == MailProtocol.NormalizeIncoming(id))
?? IncomingProtocols[0];
public static ChoiceRow Security(string? id, bool legacySsl = true) =>
SecurityModes.FirstOrDefault(p => p.Id == MailSecurity.Normalize(id, legacySsl))
?? SecurityModes[1];
public static ChoiceRow Provider(string? id) =>
Providers.FirstOrDefault(p => p.Id == MailProvider.Normalize(id))
?? Providers[0];
public static IReadOnlyList<ChoiceRow> CertifiedKinds =>
[
new() { Id = MailCertifiedKind.Ordinary, Title = UiLocale.Copy.CertifiedOrdinary },
new() { Id = MailCertifiedKind.Pec, Title = UiLocale.Copy.CertifiedPec },
new() { Id = MailCertifiedKind.Rem, Title = UiLocale.Copy.CertifiedRem }
];
public static ChoiceRow Certified(string? id) =>
CertifiedKinds.FirstOrDefault(p => p.Id == MailCertifiedKind.Normalize(id))
?? CertifiedKinds[0];
public static IReadOnlyList<ChoiceRow> ProvidersFor(FeatureSettings features, string? keepId = null) {
features ??= new FeatureSettings();
var rows = Providers.Where(p => {
if (p.Id is MailProvider.Imap or MailProvider.Gmail or MailProvider.Outlook)
return true;
if (MailProvider.IsRemPreset(p.Id))
return features.IsEnabled(AppFeature.RemPresets);
if (MailProvider.IsItalianPec(p.Id))
return features.IsEnabled(AppFeature.PecPresets);
return true;
}).ToList();
var keep = Provider(keepId);
if (rows.All(p => p.Id != keep.Id))
rows.Add(keep);
return rows;
}
}
public sealed partial class FolderRowViewModel : ObservableObject {
public required string FullName { get; init; }
public char Delimiter { get; init; }
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(Line))]
private string name = "";
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(Line))]
[NotifyPropertyChangedFor(nameof(UnreadLabel))]
[NotifyPropertyChangedFor(nameof(HasUnread))]
private int unread;
[ObservableProperty]
private int total;
public string Line =>
HasUnread ? $"{Name} ({Unread})" : Name;
public string UnreadLabel =>
Unread > 0 ? Unread.ToString() : "";
public bool HasUnread =>
Unread > 0;
}
public sealed partial class FolderNodeViewModel : ObservableObject {
public bool IsAccount { get; init; }
public MailboxAccount? Mailbox { get; init; }
public FolderRowViewModel? Folder { get; init; }
[ObservableProperty]
private bool isExpanded = true;
public ObservableCollection<FolderNodeViewModel> Children { get; } = [];
public string Title =>
IsAccount ? Mailbox?.Label ?? UiLocale.Copy.Mailbox : Folder?.Name ?? "";
public string Glyph =>
IsAccount ? "✉" : MailFolderRole.Glyph(Folder?.Name, Folder?.FullName);
public int Unread =>
IsAccount ? ChildUnread() : Folder?.Unread ?? 0;
private int ChildUnread() {
var n = 0;
foreach (var child in Children) {
n += child.Folder?.Unread ?? 0;
n += child.ChildUnread();
}
return n;
}
public string UnreadLabel =>
Unread > 0 ? Unread.ToString() : "";
public bool HasUnread =>
Unread > 0;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(RetentionLabel))]
[NotifyPropertyChangedFor(nameof(HasRetention))]
private int retentionDays;
public string RetentionLabel =>
UiLocale.Copy.RetentionBadge(RetentionDays);
public bool HasRetention =>
RetentionDays > 0;
public MailboxQuota? Quota { get; set; }
public bool ShowQuota =>
IsAccount && Quota?.Percent is int;
public double QuotaPercent =>
Quota?.Percent ?? 0;
public string QuotaTip =>
Quota?.Line() ?? "";
public FontWeight Weight =>
HasUnread ? FontWeight.SemiBold : FontWeight.Normal;
public void NotifyCounts() {
OnPropertyChanged(nameof(Title));
OnPropertyChanged(nameof(Unread));
OnPropertyChanged(nameof(UnreadLabel));
OnPropertyChanged(nameof(HasUnread));
OnPropertyChanged(nameof(Weight));
OnPropertyChanged(nameof(RetentionLabel));
OnPropertyChanged(nameof(HasRetention));
}
public void NotifyQuota() {
OnPropertyChanged(nameof(Quota));
OnPropertyChanged(nameof(ShowQuota));
OnPropertyChanged(nameof(QuotaPercent));
OnPropertyChanged(nameof(QuotaTip));
}
public static FolderNodeViewModel Account(MailboxAccount box, bool expanded = true) =>
new() {
IsAccount = true,
Mailbox = box,
IsExpanded = expanded
};
public static FolderNodeViewModel ForFolder(MailboxAccount box, FolderRowViewModel folder, bool expanded = true) {
var node = new FolderNodeViewModel {
Mailbox = box,
Folder = folder,
IsExpanded = expanded
};
folder.PropertyChanged += (_, _) => node.NotifyCounts();
return node;
}
}
public sealed class MessageRowViewModel : ObservableObject {
public string MailboxId { get; set; } = "";
public required MailMessageHeader Header { get; set; }
public string Subject =>
string.IsNullOrWhiteSpace(Header.Subject) ? UiLocale.Copy.NoSubject : Header.Subject;
public int ChainDepth { get; private set; }
public int ChainSize { get; private set; } = 1;
public string ChainSubject {
get {
if (ChainDepth > 0)
return "↳ " + Subject;
if (ChainSize > 1)
return Subject + " · " + ChainSize;
return Subject;
}
}
public Thickness SubjectPad =>
new(6 + ChainDepth * 12, 0, 6, 0);
public void SetChain(int depth, int size) {
ChainDepth = Math.Max(0, depth);
ChainSize = Math.Max(1, size);
OnPropertyChanged(nameof(ChainSubject));
OnPropertyChanged(nameof(SubjectPad));
}
public string From =>
Header.From;
public string When =>
MailWhen.Line(Header.Date);
public DateTimeOffset SortDate =>
Header.Date;
public int UnreadSort =>
Header.IsSeen ? 1 : 0;
public int FlagSort =>
Header.IsFlagged ? 0 : 1;
public int PrioritySort =>
Header.Priority == MailPriority.High ? 0 : Header.Priority == MailPriority.Low ? 2 : 1;
public int AttachmentSort =>
Header.HasAttachments ? 0 : 1;
public int DeliverySort =>
ReceiptStatus.Rank(Header.DeliveryStatus);
public string Badge =>
Header.EnvelopeBadge;
public string UnreadMark =>
Header.IsSeen ? "" : "●";
public string UnreadTip =>
Header.IsSeen ? UiLocale.Copy.Read : UiLocale.Copy.Unread;
public string AttachmentMark =>
Header.HasAttachments ? "📎" : "";
public string AttachmentTip =>
Header.HasAttachments ? UiLocale.Copy.HasAttachments : UiLocale.Copy.NoAttachments;
public string FlagMark =>
Header.IsFlagged ? "★" : "☆";
public string FlagTip =>
Header.IsFlagged ? UiLocale.Copy.Flagged : UiLocale.Copy.NotFlagged;
public string DeliveryMark =>
ReceiptStatus.Mark(Header.DeliveryStatus);
public string DeliveryLabel =>
ReceiptStatus.Label(Header.DeliveryStatus);
public string DeliveryTip =>
string.IsNullOrWhiteSpace(DeliveryLabel) ? UiLocale.Copy.NoDelivery : DeliveryLabel;
public string PriorityMark =>
MailPriority.Mark(Header.Priority);
public string PriorityTip =>
MailPriority.Label(Header.Priority);
public string BadgeTip =>
EnvelopeKind.Label(Header.EnvelopeKind);
public string Labels =>
Header.Labels;
public FontWeight Weight =>
Header.IsSeen ? FontWeight.Normal : FontWeight.SemiBold;
public void RefreshMarks() {
OnPropertyChanged(nameof(Subject));
OnPropertyChanged(nameof(ChainSubject));
OnPropertyChanged(nameof(UnreadMark));
OnPropertyChanged(nameof(UnreadTip));
OnPropertyChanged(nameof(FlagMark));
OnPropertyChanged(nameof(FlagTip));
OnPropertyChanged(nameof(PriorityMark));
OnPropertyChanged(nameof(PriorityTip));
OnPropertyChanged(nameof(AttachmentMark));
OnPropertyChanged(nameof(AttachmentTip));
OnPropertyChanged(nameof(DeliveryMark));
OnPropertyChanged(nameof(DeliveryLabel));
OnPropertyChanged(nameof(DeliveryTip));
OnPropertyChanged(nameof(Labels));
OnPropertyChanged(nameof(Weight));
}
}