Merge read receipt tracking work

This commit is contained in:
Burak Kaan Köse
2026-04-11 21:03:22 +02:00
29 changed files with 692 additions and 21 deletions
@@ -124,6 +124,9 @@ public partial class ComposePageViewModel : MailBaseViewModel,
[ObservableProperty]
public partial bool IsSmimeEncryptionEnabled { get; set; }
[ObservableProperty]
public partial bool IsReadReceiptRequested { get; set; }
[ObservableProperty]
public partial X509Certificate2 SelectedSigningCertificate { get; set; }
@@ -422,6 +425,7 @@ public partial class ComposePageViewModel : MailBaseViewModel,
SaveImportance();
SaveSubject();
SaveFromAddress();
SaveReadReceiptRequest();
SaveReplyToAddress();
await SaveAttachmentsAsync();
@@ -753,6 +757,9 @@ public partial class ComposePageViewModel : MailBaseViewModel,
IsCCBCCVisible = true;
Subject = replyingMime.Subject;
IsReadReceiptRequested = replyingMime.HasReadReceiptRequest();
Messenger.Send(new CreateNewComposeMailRequested(renderModel));
});
if (RenderHtmlBodyAsyncFunc != null)
@@ -818,6 +825,15 @@ public partial class ComposePageViewModel : MailBaseViewModel,
}
}
private void SaveReadReceiptRequest()
{
if (CurrentMimeMessage == null)
return;
var receiptAddress = SelectedAlias?.AliasAddress ?? ComposingAccount?.Address ?? string.Empty;
CurrentMimeMessage.SetReadReceiptRequest(receiptAddress, IsReadReceiptRequested);
}
private void SaveAddressInfo(IEnumerable<AccountContact> addresses, InternetAddressList list)
{
list.Clear();
@@ -68,6 +68,9 @@ public partial class AccountContactViewModel : ObservableObject, IMailItemDispla
public DateTime CreationDate => default;
public bool IsBusy => false;
public bool IsThreadExpanded => false;
public bool HasReadReceiptTracking => false;
public bool IsReadReceiptAcknowledged => false;
public string ReadReceiptDisplayText => string.Empty;
public AccountContact SenderContact => new()
{
Address = Address,
@@ -1,6 +1,7 @@
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.Enums;
@@ -105,6 +106,17 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient,
set => SetProperty(MailCopy.IsDraft, value, MailCopy, (u, n) => u.IsDraft = n);
}
public bool HasReadReceiptTracking => MailCopy.IsReadReceiptRequested;
public bool IsReadReceiptAcknowledged => MailCopy.ReadReceiptStatus == SentMailReceiptStatus.Acknowledged;
public string ReadReceiptDisplayText => MailCopy.ReadReceiptStatus switch
{
SentMailReceiptStatus.Acknowledged => Translator.MailReceiptStatus_Acknowledged,
SentMailReceiptStatus.Requested => Translator.MailReceiptStatus_Requested,
_ => string.Empty
};
public string DraftId
{
get => MailCopy.DraftId;
@@ -225,6 +237,7 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient,
nameof(IsFocused) => MailCopyChangeFlags.IsFocused,
nameof(IsRead) => MailCopyChangeFlags.IsRead,
nameof(IsDraft) => MailCopyChangeFlags.IsDraft,
nameof(HasReadReceiptTracking) or nameof(IsReadReceiptAcknowledged) or nameof(ReadReceiptDisplayText) => MailCopyChangeFlags.ReadReceiptState,
nameof(DraftId) => MailCopyChangeFlags.DraftId,
nameof(Id) => MailCopyChangeFlags.Id,
nameof(Subject) => MailCopyChangeFlags.Subject,
@@ -287,6 +300,10 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient,
changedFlags |= SetIfChanged(MailCopy.AssignedAccount, source.AssignedAccount, value => MailCopy.AssignedAccount = value, MailCopyChangeFlags.AssignedAccount);
changedFlags |= SetIfChanged(MailCopy.AssignedFolder, source.AssignedFolder, value => MailCopy.AssignedFolder = value, MailCopyChangeFlags.AssignedFolder);
changedFlags |= SetIfChanged(MailCopy.UniqueId, source.UniqueId, value => MailCopy.UniqueId = value, MailCopyChangeFlags.UniqueId);
changedFlags |= SetIfChanged(MailCopy.IsReadReceiptRequested, source.IsReadReceiptRequested, value => MailCopy.IsReadReceiptRequested = value, MailCopyChangeFlags.ReadReceiptState);
changedFlags |= SetIfChanged(MailCopy.ReadReceiptStatus, source.ReadReceiptStatus, value => MailCopy.ReadReceiptStatus = value, MailCopyChangeFlags.ReadReceiptState);
changedFlags |= SetIfChanged(MailCopy.ReadReceiptAcknowledgedAtUtc, source.ReadReceiptAcknowledgedAtUtc, value => MailCopy.ReadReceiptAcknowledgedAtUtc = value, MailCopyChangeFlags.ReadReceiptState);
changedFlags |= SetIfChanged(MailCopy.ReadReceiptMessageUniqueId, source.ReadReceiptMessageUniqueId, value => MailCopy.ReadReceiptMessageUniqueId = value, MailCopyChangeFlags.ReadReceiptState);
}
changedFlags |= changeHint;
@@ -358,6 +375,13 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient,
if ((changedFlags & MailCopyChangeFlags.IsDraft) != 0)
Queue(nameof(IsDraft));
if ((changedFlags & MailCopyChangeFlags.ReadReceiptState) != 0)
{
Queue(nameof(HasReadReceiptTracking));
Queue(nameof(IsReadReceiptAcknowledged));
Queue(nameof(ReadReceiptDisplayText));
}
if ((changedFlags & MailCopyChangeFlags.DraftId) != 0)
Queue(nameof(DraftId));
@@ -100,6 +100,12 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IMailListIte
/// </summary>
public bool IsRead => ThreadEmails.All(e => e.IsRead);
public bool HasReadReceiptTracking => latestMailViewModel?.HasReadReceiptTracking ?? false;
public bool IsReadReceiptAcknowledged => latestMailViewModel?.IsReadReceiptAcknowledged ?? false;
public string ReadReceiptDisplayText => latestMailViewModel?.ReadReceiptDisplayText ?? string.Empty;
/// <summary>
/// Gets whether any email in this thread is a draft
/// </summary>
@@ -177,6 +183,9 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IMailListIte
[NotifyPropertyChangedFor(nameof(IsFlagged))]
[NotifyPropertyChangedFor(nameof(IsFocused))]
[NotifyPropertyChangedFor(nameof(IsRead))]
[NotifyPropertyChangedFor(nameof(HasReadReceiptTracking))]
[NotifyPropertyChangedFor(nameof(IsReadReceiptAcknowledged))]
[NotifyPropertyChangedFor(nameof(ReadReceiptDisplayText))]
[NotifyPropertyChangedFor(nameof(IsDraft))]
[NotifyPropertyChangedFor(nameof(DraftId))]
[NotifyPropertyChangedFor(nameof(Id))]
@@ -451,6 +460,13 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IMailListIte
if ((changedFlags & MailCopyChangeFlags.IsRead) != 0 || changedFlags == MailCopyChangeFlags.All)
Queue(nameof(IsRead));
if ((changedFlags & MailCopyChangeFlags.ReadReceiptState) != 0 || changedFlags == MailCopyChangeFlags.All)
{
Queue(nameof(HasReadReceiptTracking));
Queue(nameof(IsReadReceiptAcknowledged));
Queue(nameof(ReadReceiptDisplayText));
}
if ((changedFlags & MailCopyChangeFlags.IsDraft) != 0 || changedFlags == MailCopyChangeFlags.All)
Queue(nameof(IsDraft));
@@ -164,10 +164,13 @@ public partial class MessageListPageViewModel : MailBaseViewModel
public Guid? ContactPictureFileId => null;
public bool ThumbnailUpdatedEvent => false;
public bool IsThreadExpanded => false;
public bool HasReadReceiptTracking => true;
public bool IsReadReceiptAcknowledged => false;
public string ReadReceiptDisplayText => Translator.MailReceiptStatus_Requested;
public AccountContact SenderContact => new()
{
Address = "ava@contoso.com",
Name = "Ava Brooks"
Address = "hi@bkaan.dev",
Name = "Burak Kaan Köse"
};
}
}