From b343152f144be5508a9e85c454e2209a437290ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Tue, 27 Jan 2026 20:37:18 +0100 Subject: [PATCH] Some experiments. --- Wino.Core/Synchronizers/GmailSynchronizer.cs | 10 ++- .../Synchronizers/OutlookSynchronizer.cs | 10 ++- .../Collections/WinoMailCollection.cs | 13 ++-- Wino.Mail.ViewModels/ComposePageViewModel.cs | 2 +- .../Data/MailItemViewModel.cs | 63 +++++++++++++++++++ .../Data/ThreadMailItemViewModel.cs | 34 ++++++++++ Wino.Mail.ViewModels/MailListPageViewModel.cs | 2 - 7 files changed, 123 insertions(+), 11 deletions(-) diff --git a/Wino.Core/Synchronizers/GmailSynchronizer.cs b/Wino.Core/Synchronizers/GmailSynchronizer.cs index d8a02bd4..5de8df59 100644 --- a/Wino.Core/Synchronizers/GmailSynchronizer.cs +++ b/Wino.Core/Synchronizers/GmailSynchronizer.cs @@ -1309,6 +1309,14 @@ public class GmailSynchronizer : WinoSynchronizer> 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 batchedBundles = batchedRequests.Batch((int)MaximumAllowedBatchRequestSize); var bundleCount = batchedBundles.Count(); @@ -1325,7 +1333,7 @@ public class GmailSynchronizer : WinoSynchronizer(requestBundle.NativeRequest, (content, error, index, message) => bundleTasks.Add(ProcessSingleNativeRequestResponseAsync(requestBundle, error, message, cancellationToken))); diff --git a/Wino.Core/Synchronizers/OutlookSynchronizer.cs b/Wino.Core/Synchronizers/OutlookSynchronizer.cs index 5fe46078..7934969d 100644 --- a/Wino.Core/Synchronizers/OutlookSynchronizer.cs +++ b/Wino.Core/Synchronizers/OutlookSynchronizer.cs @@ -1506,6 +1506,14 @@ public class OutlookSynchronizer : WinoSynchronizer> 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); foreach (var batch in batchedGroups) @@ -1542,7 +1550,7 @@ public class OutlookSynchronizer : WinoSynchronizer { - existingItem.MailCopy = updatedItem; + existingItem.UpdateFrom(updatedItem); }); UpdateUniqueIdHashes(existingItem, true); @@ -574,7 +574,7 @@ public class WinoMailCollection : ObservableRecipient, IRecipient - /// 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. /// /// Updated mail copy. /// @@ -739,8 +739,9 @@ public class WinoMailCollection : ObservableRecipient, IRecipient { - CurrentMailDraftItem.MailCopy = updatedMail; + CurrentMailDraftItem.UpdateFrom(updatedMail); DiscardCommand.NotifyCanExecuteChanged(); SendCommand.NotifyCanExecuteChanged(); }); diff --git a/Wino.Mail.ViewModels/Data/MailItemViewModel.cs b/Wino.Mail.ViewModels/Data/MailItemViewModel.cs index 422cebc4..e15493a9 100644 --- a/Wino.Mail.ViewModels/Data/MailItemViewModel.cs +++ b/Wino.Mail.ViewModels/Data/MailItemViewModel.cs @@ -184,4 +184,67 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient, yield return this; } } + + /// + /// 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. + /// + /// The source MailCopy with updated values. + 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)); + } } diff --git a/Wino.Mail.ViewModels/Data/ThreadMailItemViewModel.cs b/Wino.Mail.ViewModels/Data/ThreadMailItemViewModel.cs index 6987d94a..6ffe5790 100644 --- a/Wino.Mail.ViewModels/Data/ThreadMailItemViewModel.cs +++ b/Wino.Mail.ViewModels/Data/ThreadMailItemViewModel.cs @@ -213,6 +213,40 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IMailListIte } } + /// + /// 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. + /// + /// The mail item that was updated (can be null to refresh all). + 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)); + } + /// /// Checks if this thread contains an email with the specified unique ID /// diff --git a/Wino.Mail.ViewModels/MailListPageViewModel.cs b/Wino.Mail.ViewModels/MailListPageViewModel.cs index 92f5bd9f..c8905d51 100644 --- a/Wino.Mail.ViewModels/MailListPageViewModel.cs +++ b/Wino.Mail.ViewModels/MailListPageViewModel.cs @@ -668,8 +668,6 @@ public partial class MailListPageViewModel : MailBaseViewModel, { base.OnMailUpdated(updatedMail); - Debug.WriteLine($"Updating {updatedMail.Id}-> {updatedMail.UniqueId}"); - await MailCollection.UpdateMailCopy(updatedMail); await ExecuteUIThread(() => { SetupTopBarActions(); });