diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
index 063e7d45..91271c54 100644
--- a/.github/copilot-instructions.md
+++ b/.github/copilot-instructions.md
@@ -100,6 +100,7 @@ _dialogService.InfoBarMessage(Translator.Info_MissingFolderTitle, message);
- **NEVER** create IValueConverter classes or add them to Converters.xaml
- **NEVER** use BoolToVisibilityConverter - WinUI 3 SDK automatically converts bool to Visibility
- Direct binding: `Visibility="{x:Bind IsVisible, Mode=OneWay}"`
+- Register control events (for example `Loaded`, `Unloaded`, `SizeChanged`, `PointerEntered`) in XAML markup, not with `+=` in `.xaml.cs`.
### XamlHelpers for Complex Conversions
- **ALWAYS** use XamlHelpers static methods instead of converters
diff --git a/Wino.Core.Domain/Interfaces/IMailItemDisplayInformation.cs b/Wino.Core.Domain/Interfaces/IMailItemDisplayInformation.cs
index af9dd221..0c2184cc 100644
--- a/Wino.Core.Domain/Interfaces/IMailItemDisplayInformation.cs
+++ b/Wino.Core.Domain/Interfaces/IMailItemDisplayInformation.cs
@@ -22,7 +22,6 @@ public interface IMailItemDisplayInformation : INotifyPropertyChanged
DateTime CreationDate { get; }
string Base64ContactPicture { get; }
bool ThumbnailUpdatedEvent { get; }
- bool IsBusy { get; }
bool IsThreadExpanded { get; }
AccountContact SenderContact { get; }
}
diff --git a/Wino.Mail.ViewModels/Data/IMailListItem.cs b/Wino.Mail.ViewModels/Data/IMailListItem.cs
index 0d6ffaf6..957915ba 100644
--- a/Wino.Mail.ViewModels/Data/IMailListItem.cs
+++ b/Wino.Mail.ViewModels/Data/IMailListItem.cs
@@ -32,6 +32,11 @@ public interface IMailListItem : IMailHashContainer, IMailListItemSorting, INoti
///
bool IsSelected { get; set; }
+ ///
+ /// Gets whether this item is currently processing a network operation.
+ ///
+ bool IsBusy { get; }
+
///
/// Gets all selected mail items within this list item.
/// For MailItemViewModel: returns itself if IsSelected is true, otherwise empty
diff --git a/Wino.Mail.WinUI/Controls/MailItemDisplayInformationControl.xaml b/Wino.Mail.WinUI/Controls/MailItemDisplayInformationControl.xaml
index 8f6c788d..e56972dd 100644
--- a/Wino.Mail.WinUI/Controls/MailItemDisplayInformationControl.xaml
+++ b/Wino.Mail.WinUI/Controls/MailItemDisplayInformationControl.xaml
@@ -19,7 +19,8 @@
FocusVisualSecondaryBrush="{StaticResource SystemControlFocusVisualSecondaryBrush}"
FocusVisualSecondaryThickness="1"
PointerEntered="ControlPointerEntered"
- PointerExited="ControlPointerExited">
+ PointerExited="ControlPointerExited"
+ Unloaded="OnUnloaded">
+ CornerRadius="4"
+ SizeChanged="RootContainerVisualWrapperSizeChanged" />
@@ -247,7 +249,7 @@
Height="3"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
- IsActive="{x:Bind MailItemInformation.IsBusy, Mode=OneWay}" />
+ IsActive="{x:Bind ActionItem.IsBusy, Mode=OneWay, FallbackValue=False}" />
diff --git a/Wino.Mail.WinUI/Controls/MailItemDisplayInformationControl.xaml.cs b/Wino.Mail.WinUI/Controls/MailItemDisplayInformationControl.xaml.cs
index 97ba5cbc..372071bb 100644
--- a/Wino.Mail.WinUI/Controls/MailItemDisplayInformationControl.xaml.cs
+++ b/Wino.Mail.WinUI/Controls/MailItemDisplayInformationControl.xaml.cs
@@ -1,4 +1,5 @@
using System;
+using System.ComponentModel;
using System.Linq;
using System.Numerics;
using CommunityToolkit.WinUI;
@@ -26,6 +27,8 @@ public sealed partial class MailItemDisplayInformationControl : UserControl
private Compositor? _compositor;
private Visual? _contentVisual;
private ScalarKeyFrameAnimation? _opacityAnimation;
+ private SpriteVisual? _leftBackgroundVisual;
+ private INotifyPropertyChanged? _actionItemPropertySource;
[GeneratedDependencyProperty(DefaultValue = MailListDisplayMode.Spacious)]
public partial MailListDisplayMode DisplayMode { get; set; }
@@ -83,8 +86,8 @@ public sealed partial class MailItemDisplayInformationControl : UserControl
var compositor = this.Visual().Compositor;
- var leftBackgroundVisual = compositor.CreateSpriteVisual();
- RootContainerVisualWrapper.SetChildVisual(leftBackgroundVisual);
+ _leftBackgroundVisual = compositor.CreateSpriteVisual();
+ RootContainerVisualWrapper.SetChildVisual(_leftBackgroundVisual);
MainContentContainer.EnableImplicitAnimation(VisualPropertyType.Offset, 400);
RootContainer.EnableImplicitAnimation(VisualPropertyType.Offset, 400);
@@ -92,8 +95,6 @@ public sealed partial class MailItemDisplayInformationControl : UserControl
ContentStackpanel.EnableImplicitAnimation(VisualPropertyType.Offset, 400);
IconsContainer.EnableImplicitAnimation(VisualPropertyType.Offset, 400);
- RootContainerVisualWrapper.SizeChanged += (s, e) => leftBackgroundVisual.Size = e.NewSize.ToVector2();
-
// Initialize shimmer effect compositor
_compositor = this.Visual().Compositor;
}
@@ -108,6 +109,23 @@ public sealed partial class MailItemDisplayInformationControl : UserControl
UpdateBusyAnimationState();
}
+ partial void OnActionItemPropertyChanged(DependencyPropertyChangedEventArgs e)
+ {
+ if (_actionItemPropertySource != null)
+ {
+ _actionItemPropertySource.PropertyChanged -= ActionItemPropertyChanged;
+ _actionItemPropertySource = null;
+ }
+
+ if (e.NewValue is INotifyPropertyChanged propertyChangedSource)
+ {
+ _actionItemPropertySource = propertyChangedSource;
+ _actionItemPropertySource.PropertyChanged += ActionItemPropertyChanged;
+ }
+
+ UpdateBusyAnimationState();
+ }
+
private void StartBusyAnimation()
{
if (_compositor == null) return;
@@ -144,7 +162,7 @@ public sealed partial class MailItemDisplayInformationControl : UserControl
private void UpdateBusyAnimationState()
{
- if (MailItemInformation?.IsBusy == true)
+ if (ActionItem?.IsBusy == true)
{
StartBusyAnimation();
return;
@@ -153,6 +171,33 @@ public sealed partial class MailItemDisplayInformationControl : UserControl
StopBusyAnimation();
}
+ private void ActionItemPropertyChanged(object? sender, PropertyChangedEventArgs e)
+ {
+ if (string.IsNullOrEmpty(e.PropertyName) || e.PropertyName == nameof(IMailListItem.IsBusy))
+ {
+ UpdateBusyAnimationState();
+ }
+ }
+
+ private void OnUnloaded(object sender, RoutedEventArgs e)
+ {
+ if (_actionItemPropertySource != null)
+ {
+ _actionItemPropertySource.PropertyChanged -= ActionItemPropertyChanged;
+ _actionItemPropertySource = null;
+ }
+
+ StopBusyAnimation();
+ }
+
+ private void RootContainerVisualWrapperSizeChanged(object sender, SizeChangedEventArgs e)
+ {
+ if (_leftBackgroundVisual != null)
+ {
+ _leftBackgroundVisual.Size = e.NewSize.ToVector2();
+ }
+ }
+
private void ControlPointerEntered(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
{
if (IsHoverActionsEnabled)