Some experiments.
This commit is contained in:
@@ -1309,6 +1309,14 @@ public class GmailSynchronizer : WinoSynchronizer<IClientServiceRequest, Message
|
|||||||
public override async Task ExecuteNativeRequestsAsync(List<IRequestBundle<IClientServiceRequest>> batchedRequests,
|
public override async Task ExecuteNativeRequestsAsync(List<IRequestBundle<IClientServiceRequest>> batchedRequests,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
// First apply all UI changes immediately before any batching.
|
||||||
|
// This ensures UI reflects changes right away, regardless of batch processing.
|
||||||
|
foreach (var bundle in batchedRequests)
|
||||||
|
{
|
||||||
|
bundle.UIChangeRequest?.ApplyUIChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now batch and execute the network requests.
|
||||||
var batchedBundles = batchedRequests.Batch((int)MaximumAllowedBatchRequestSize);
|
var batchedBundles = batchedRequests.Batch((int)MaximumAllowedBatchRequestSize);
|
||||||
var bundleCount = batchedBundles.Count();
|
var bundleCount = batchedBundles.Count();
|
||||||
|
|
||||||
@@ -1325,7 +1333,7 @@ public class GmailSynchronizer : WinoSynchronizer<IClientServiceRequest, Message
|
|||||||
for (int k = 0; k < bundleRequestCount; k++)
|
for (int k = 0; k < bundleRequestCount; k++)
|
||||||
{
|
{
|
||||||
var requestBundle = bundle.ElementAt(k);
|
var requestBundle = bundle.ElementAt(k);
|
||||||
requestBundle.UIChangeRequest?.ApplyUIChanges();
|
// UI changes are already applied above before batching.
|
||||||
|
|
||||||
nativeBatchRequest.Queue<object>(requestBundle.NativeRequest, (content, error, index, message)
|
nativeBatchRequest.Queue<object>(requestBundle.NativeRequest, (content, error, index, message)
|
||||||
=> bundleTasks.Add(ProcessSingleNativeRequestResponseAsync(requestBundle, error, message, cancellationToken)));
|
=> bundleTasks.Add(ProcessSingleNativeRequestResponseAsync(requestBundle, error, message, cancellationToken)));
|
||||||
|
|||||||
@@ -1506,6 +1506,14 @@ public class OutlookSynchronizer : WinoSynchronizer<RequestInformation, Message,
|
|||||||
|
|
||||||
public override async Task ExecuteNativeRequestsAsync(List<IRequestBundle<RequestInformation>> batchedRequests, CancellationToken cancellationToken = default)
|
public override async Task ExecuteNativeRequestsAsync(List<IRequestBundle<RequestInformation>> batchedRequests, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
// First apply all UI changes immediately before any batching.
|
||||||
|
// This ensures UI reflects changes right away, regardless of batch processing.
|
||||||
|
foreach (var bundle in batchedRequests)
|
||||||
|
{
|
||||||
|
bundle.UIChangeRequest?.ApplyUIChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now batch and execute the network requests.
|
||||||
var batchedGroups = batchedRequests.Batch((int)MaximumAllowedBatchRequestSize);
|
var batchedGroups = batchedRequests.Batch((int)MaximumAllowedBatchRequestSize);
|
||||||
|
|
||||||
foreach (var batch in batchedGroups)
|
foreach (var batch in batchedGroups)
|
||||||
@@ -1542,7 +1550,7 @@ public class OutlookSynchronizer : WinoSynchronizer<RequestInformation, Message,
|
|||||||
var bundle = batch.ElementAt(i);
|
var bundle = batch.ElementAt(i);
|
||||||
requiresSerial |= bundle.UIChangeRequest is SendDraftRequest;
|
requiresSerial |= bundle.UIChangeRequest is SendDraftRequest;
|
||||||
|
|
||||||
bundle.UIChangeRequest?.ApplyUIChanges();
|
// UI changes are already applied in ExecuteNativeRequestsAsync before batching.
|
||||||
var batchRequestId = await batchContent.AddBatchRequestStepAsync(bundle.NativeRequest);
|
var batchRequestId = await batchContent.AddBatchRequestStepAsync(bundle.NativeRequest);
|
||||||
bundle.BundleId = batchRequestId;
|
bundle.BundleId = batchRequestId;
|
||||||
bundleIdMap[batchRequestId] = bundle;
|
bundleIdMap[batchRequestId] = bundle;
|
||||||
|
|||||||
@@ -444,7 +444,7 @@ public class WinoMailCollection : ObservableRecipient, IRecipient<SelectedItemsC
|
|||||||
|
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThread(() =>
|
||||||
{
|
{
|
||||||
existingItem.MailCopy = updatedItem;
|
existingItem.UpdateFrom(updatedItem);
|
||||||
});
|
});
|
||||||
|
|
||||||
UpdateUniqueIdHashes(existingItem, true);
|
UpdateUniqueIdHashes(existingItem, true);
|
||||||
@@ -574,7 +574,7 @@ public class WinoMailCollection : ObservableRecipient, IRecipient<SelectedItemsC
|
|||||||
foreach (var (existing, updated) in itemsToUpdate)
|
foreach (var (existing, updated) in itemsToUpdate)
|
||||||
{
|
{
|
||||||
UpdateUniqueIdHashes(existing, false);
|
UpdateUniqueIdHashes(existing, false);
|
||||||
existing.MailCopy = updated;
|
existing.UpdateFrom(updated);
|
||||||
UpdateUniqueIdHashes(existing, true);
|
UpdateUniqueIdHashes(existing, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -720,7 +720,7 @@ public class WinoMailCollection : ObservableRecipient, IRecipient<SelectedItemsC
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fins the item container that updated mail copy belongs to and updates it.
|
/// Finds the item container that updated mail copy belongs to and updates it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="updatedMailCopy">Updated mail copy.</param>
|
/// <param name="updatedMailCopy">Updated mail copy.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
@@ -739,8 +739,9 @@ public class WinoMailCollection : ObservableRecipient, IRecipient<SelectedItemsC
|
|||||||
{
|
{
|
||||||
UpdateUniqueIdHashes(itemContainer.ItemViewModel, false);
|
UpdateUniqueIdHashes(itemContainer.ItemViewModel, false);
|
||||||
|
|
||||||
// Update the MailCopy - this will automatically notify all dependent properties
|
// Update the MailCopy using UpdateFrom to properly notify all XAML bindings
|
||||||
itemContainer.ItemViewModel.MailCopy = updatedMailCopy;
|
// This maintains reference integrity and ensures PropertyChanged is raised for all properties
|
||||||
|
itemContainer.ItemViewModel.UpdateFrom(updatedMailCopy);
|
||||||
|
|
||||||
UpdateUniqueIdHashes(itemContainer.ItemViewModel, true);
|
UpdateUniqueIdHashes(itemContainer.ItemViewModel, true);
|
||||||
}
|
}
|
||||||
@@ -748,7 +749,7 @@ public class WinoMailCollection : ObservableRecipient, IRecipient<SelectedItemsC
|
|||||||
// Trigger thread property notifications if this item is in a thread
|
// Trigger thread property notifications if this item is in a thread
|
||||||
if (itemContainer.ThreadViewModel != null)
|
if (itemContainer.ThreadViewModel != null)
|
||||||
{
|
{
|
||||||
itemContainer.ThreadViewModel.ThreadEmails = itemContainer.ThreadViewModel.ThreadEmails;
|
itemContainer.ThreadViewModel.NotifyMailItemUpdated(itemContainer.ItemViewModel);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -643,7 +643,7 @@ public partial class ComposePageViewModel : MailBaseViewModel
|
|||||||
{
|
{
|
||||||
await ExecuteUIThread(() =>
|
await ExecuteUIThread(() =>
|
||||||
{
|
{
|
||||||
CurrentMailDraftItem.MailCopy = updatedMail;
|
CurrentMailDraftItem.UpdateFrom(updatedMail);
|
||||||
DiscardCommand.NotifyCanExecuteChanged();
|
DiscardCommand.NotifyCanExecuteChanged();
|
||||||
SendCommand.NotifyCanExecuteChanged();
|
SendCommand.NotifyCanExecuteChanged();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -184,4 +184,67 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient,
|
|||||||
yield return this;
|
yield return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the MailCopy with new data and notifies all bound properties.
|
||||||
|
/// This method copies values from the source to the existing MailCopy to maintain reference integrity,
|
||||||
|
/// then explicitly raises PropertyChanged for all dependent properties.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">The source MailCopy with updated values.</param>
|
||||||
|
public void UpdateFrom(MailCopy source)
|
||||||
|
{
|
||||||
|
if (source == null) return;
|
||||||
|
|
||||||
|
// Update the underlying MailCopy properties directly to maintain reference integrity
|
||||||
|
// This is important because other parts of the app may hold references to this MailCopy
|
||||||
|
// Note: UniqueId is the primary key and should match - we don't update it
|
||||||
|
MailCopy.Id = source.Id;
|
||||||
|
MailCopy.FolderId = source.FolderId;
|
||||||
|
MailCopy.ThreadId = source.ThreadId;
|
||||||
|
MailCopy.MessageId = source.MessageId;
|
||||||
|
MailCopy.References = source.References;
|
||||||
|
MailCopy.InReplyTo = source.InReplyTo;
|
||||||
|
MailCopy.IsDraft = source.IsDraft;
|
||||||
|
MailCopy.DraftId = source.DraftId;
|
||||||
|
MailCopy.CreationDate = source.CreationDate;
|
||||||
|
MailCopy.Subject = source.Subject;
|
||||||
|
MailCopy.PreviewText = source.PreviewText;
|
||||||
|
MailCopy.FromName = source.FromName;
|
||||||
|
MailCopy.FromAddress = source.FromAddress;
|
||||||
|
MailCopy.HasAttachments = source.HasAttachments;
|
||||||
|
MailCopy.Importance = source.Importance;
|
||||||
|
MailCopy.IsRead = source.IsRead;
|
||||||
|
MailCopy.IsFlagged = source.IsFlagged;
|
||||||
|
MailCopy.IsFocused = source.IsFocused;
|
||||||
|
MailCopy.FileId = source.FileId;
|
||||||
|
MailCopy.ItemType = source.ItemType;
|
||||||
|
MailCopy.SenderContact = source.SenderContact;
|
||||||
|
MailCopy.AssignedAccount = source.AssignedAccount;
|
||||||
|
MailCopy.AssignedFolder = source.AssignedFolder;
|
||||||
|
|
||||||
|
// Raise PropertyChanged for all properties that XAML may bind to
|
||||||
|
OnPropertyChanged(nameof(CreationDate));
|
||||||
|
OnPropertyChanged(nameof(IsFlagged));
|
||||||
|
OnPropertyChanged(nameof(FromName));
|
||||||
|
OnPropertyChanged(nameof(IsFocused));
|
||||||
|
OnPropertyChanged(nameof(IsRead));
|
||||||
|
OnPropertyChanged(nameof(IsDraft));
|
||||||
|
OnPropertyChanged(nameof(DraftId));
|
||||||
|
OnPropertyChanged(nameof(Id));
|
||||||
|
OnPropertyChanged(nameof(Subject));
|
||||||
|
OnPropertyChanged(nameof(PreviewText));
|
||||||
|
OnPropertyChanged(nameof(FromAddress));
|
||||||
|
OnPropertyChanged(nameof(HasAttachments));
|
||||||
|
OnPropertyChanged(nameof(Importance));
|
||||||
|
OnPropertyChanged(nameof(ThreadId));
|
||||||
|
OnPropertyChanged(nameof(MessageId));
|
||||||
|
OnPropertyChanged(nameof(References));
|
||||||
|
OnPropertyChanged(nameof(InReplyTo));
|
||||||
|
OnPropertyChanged(nameof(FileId));
|
||||||
|
OnPropertyChanged(nameof(FolderId));
|
||||||
|
OnPropertyChanged(nameof(UniqueId));
|
||||||
|
OnPropertyChanged(nameof(Base64ContactPicture));
|
||||||
|
OnPropertyChanged(nameof(SortingDate));
|
||||||
|
OnPropertyChanged(nameof(SortingName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -213,6 +213,40 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IMailListIte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Notifies that a mail item within this thread has been updated.
|
||||||
|
/// This raises PropertyChanged for all thread-level computed properties that depend on child items.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="updatedMailItem">The mail item that was updated (can be null to refresh all).</param>
|
||||||
|
public void NotifyMailItemUpdated(MailItemViewModel updatedMailItem)
|
||||||
|
{
|
||||||
|
// Raise PropertyChanged for all computed properties that depend on ThreadEmails contents
|
||||||
|
OnPropertyChanged(nameof(Subject));
|
||||||
|
OnPropertyChanged(nameof(FromName));
|
||||||
|
OnPropertyChanged(nameof(CreationDate));
|
||||||
|
OnPropertyChanged(nameof(FromAddress));
|
||||||
|
OnPropertyChanged(nameof(PreviewText));
|
||||||
|
OnPropertyChanged(nameof(HasAttachments));
|
||||||
|
OnPropertyChanged(nameof(IsFlagged));
|
||||||
|
OnPropertyChanged(nameof(IsFocused));
|
||||||
|
OnPropertyChanged(nameof(IsRead));
|
||||||
|
OnPropertyChanged(nameof(IsDraft));
|
||||||
|
OnPropertyChanged(nameof(DraftId));
|
||||||
|
OnPropertyChanged(nameof(Id));
|
||||||
|
OnPropertyChanged(nameof(Importance));
|
||||||
|
OnPropertyChanged(nameof(ThreadId));
|
||||||
|
OnPropertyChanged(nameof(MessageId));
|
||||||
|
OnPropertyChanged(nameof(References));
|
||||||
|
OnPropertyChanged(nameof(InReplyTo));
|
||||||
|
OnPropertyChanged(nameof(FileId));
|
||||||
|
OnPropertyChanged(nameof(FolderId));
|
||||||
|
OnPropertyChanged(nameof(UniqueId));
|
||||||
|
OnPropertyChanged(nameof(Base64ContactPicture));
|
||||||
|
OnPropertyChanged(nameof(ThumbnailUpdatedEvent));
|
||||||
|
OnPropertyChanged(nameof(SortingDate));
|
||||||
|
OnPropertyChanged(nameof(SortingName));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if this thread contains an email with the specified unique ID
|
/// Checks if this thread contains an email with the specified unique ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -668,8 +668,6 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
|||||||
{
|
{
|
||||||
base.OnMailUpdated(updatedMail);
|
base.OnMailUpdated(updatedMail);
|
||||||
|
|
||||||
Debug.WriteLine($"Updating {updatedMail.Id}-> {updatedMail.UniqueId}");
|
|
||||||
|
|
||||||
await MailCollection.UpdateMailCopy(updatedMail);
|
await MailCollection.UpdateMailCopy(updatedMail);
|
||||||
|
|
||||||
await ExecuteUIThread(() => { SetupTopBarActions(); });
|
await ExecuteUIThread(() => { SetupTopBarActions(); });
|
||||||
|
|||||||
Reference in New Issue
Block a user