From b12c9bf11d2f1f03c4dba3840924d8c9ef875640 Mon Sep 17 00:00:00 2001 From: lincube Date: Tue, 2 Jun 2026 16:31:29 +0800 Subject: [PATCH] =?UTF-8?q?fix.=E5=85=83=E7=B4=A0=E5=8A=A8=E7=94=BB?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E5=AF=BC=E8=87=B4=E7=9A=84=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E9=97=AA=E7=8E=B0=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DesktopEditOverlayPresenterTests.cs | 33 +++++++ .../DesktopEditAnimationRuntime.cs | 12 +++ .../DesktopEditing/DesktopEditGhostView.cs | 14 ++- .../DesktopEditOverlayPresenter.cs | 89 +++++++++---------- 4 files changed, 98 insertions(+), 50 deletions(-) create mode 100644 LanMountainDesktop/DesktopEditing/DesktopEditAnimationRuntime.cs diff --git a/LanMountainDesktop.Tests/DesktopEditOverlayPresenterTests.cs b/LanMountainDesktop.Tests/DesktopEditOverlayPresenterTests.cs index f6a8bc1..252a961 100644 --- a/LanMountainDesktop.Tests/DesktopEditOverlayPresenterTests.cs +++ b/LanMountainDesktop.Tests/DesktopEditOverlayPresenterTests.cs @@ -35,4 +35,37 @@ public sealed class DesktopEditOverlayPresenterTests Assert.Equal(180, ghost.Width); Assert.Equal(120, ghost.Height); } + + [Fact] + public void CandidateRectUsesCanvasPlacement() + { + var presenter = new DesktopEditOverlayPresenter(new CompositionVisualAnimationService(_ => null)); + var root = Assert.IsType(presenter.Root); + + presenter.SetCandidateRect(new Rect(44, 58, 240, 160)); + + var candidate = root.Children.OfType().Single(child => child is not DesktopEditGhostView); + Assert.Equal(44, Canvas.GetLeft(candidate)); + Assert.Equal(58, Canvas.GetTop(candidate)); + Assert.Equal(240, candidate.Width); + Assert.Equal(160, candidate.Height); + } + + [Fact] + public void ShowPreservesPreviewAndCandidateCanvasPlacement() + { + var presenter = new DesktopEditOverlayPresenter(new CompositionVisualAnimationService(_ => null)); + var root = Assert.IsType(presenter.Root); + + presenter.SetPreviewRect(new Rect(16, 32, 180, 120)); + presenter.SetCandidateRect(new Rect(24, 40, 200, 140)); + presenter.Show(); + + var ghost = root.Children.OfType().Single(); + var candidate = root.Children.OfType().Single(child => child is not DesktopEditGhostView); + Assert.Equal(16, Canvas.GetLeft(ghost)); + Assert.Equal(32, Canvas.GetTop(ghost)); + Assert.Equal(24, Canvas.GetLeft(candidate)); + Assert.Equal(40, Canvas.GetTop(candidate)); + } } diff --git a/LanMountainDesktop/DesktopEditing/DesktopEditAnimationRuntime.cs b/LanMountainDesktop/DesktopEditing/DesktopEditAnimationRuntime.cs new file mode 100644 index 0000000..bec8963 --- /dev/null +++ b/LanMountainDesktop/DesktopEditing/DesktopEditAnimationRuntime.cs @@ -0,0 +1,12 @@ +using Avalonia; +using Avalonia.Threading; + +namespace LanMountainDesktop.DesktopEditing; + +internal static class DesktopEditAnimationRuntime +{ + public static bool CanUseTransitions() + { + return Application.Current is not null && Dispatcher.UIThread.CheckAccess(); + } +} diff --git a/LanMountainDesktop/DesktopEditing/DesktopEditGhostView.cs b/LanMountainDesktop/DesktopEditing/DesktopEditGhostView.cs index a3537d5..3f54ea9 100644 --- a/LanMountainDesktop/DesktopEditing/DesktopEditGhostView.cs +++ b/LanMountainDesktop/DesktopEditing/DesktopEditGhostView.cs @@ -52,7 +52,7 @@ internal sealed class DesktopEditGhostView : Border ClipToBounds = true; RenderTransformOrigin = new RelativePoint(0.5, 0.5, RelativeUnit.Relative); RenderTransform = _scaleTransform; - if (Dispatcher.UIThread.CheckAccess()) + if (DesktopEditAnimationRuntime.CanUseTransitions()) { Transitions = new Transitions { @@ -301,6 +301,12 @@ internal sealed class DesktopEditGhostView : Border internal void SetScaleTransitionDuration(TimeSpan duration) { + if (!DesktopEditAnimationRuntime.CanUseTransitions()) + { + _scaleTransform.Transitions = null; + return; + } + _scaleTransform.Transitions = new Transitions { CreateScaleTransition(ScaleTransform.ScaleXProperty, duration), @@ -310,6 +316,12 @@ internal sealed class DesktopEditGhostView : Border internal void SetOpacityTransitionDuration(TimeSpan duration) { + if (!DesktopEditAnimationRuntime.CanUseTransitions()) + { + Transitions = null; + return; + } + Transitions = new Transitions { CreateOpacityTransition(duration) diff --git a/LanMountainDesktop/DesktopEditing/DesktopEditOverlayPresenter.cs b/LanMountainDesktop/DesktopEditing/DesktopEditOverlayPresenter.cs index 5b34887..8332b8c 100644 --- a/LanMountainDesktop/DesktopEditing/DesktopEditOverlayPresenter.cs +++ b/LanMountainDesktop/DesktopEditing/DesktopEditOverlayPresenter.cs @@ -33,8 +33,6 @@ internal sealed class DesktopEditOverlayPresenter private Rect? _candidateRect; private bool _isInvalid; private bool _isVisible; - private bool _ghostUsesCompositionOffset; - private bool _candidateUsesCompositionOffset; private int _dismissVersion; private readonly SolidColorBrush _candidateBrush = new(Color.Parse("#FF0A84FF")); @@ -68,7 +66,7 @@ internal sealed class DesktopEditOverlayPresenter RenderTransformOrigin = new RelativePoint(0.5, 0.5, RelativeUnit.Relative), RenderTransform = _candidateScale }; - if (Dispatcher.UIThread.CheckAccess()) + if (DesktopEditAnimationRuntime.CanUseTransitions()) { _candidateOutline.Transitions = new Transitions { @@ -102,7 +100,7 @@ internal sealed class DesktopEditOverlayPresenter } }; - if (Dispatcher.UIThread.CheckAccess()) + if (DesktopEditAnimationRuntime.CanUseTransitions()) { _root.Transitions = new Transitions { @@ -170,21 +168,24 @@ internal sealed class DesktopEditOverlayPresenter targetGhostScale = 1.03; } - _root.Transitions = new Transitions + if (DesktopEditAnimationRuntime.CanUseTransitions()) { - CreateOpacityTransition(PickupDuration) - }; - _ghostView.SetOpacityTransitionDuration(PickupDuration); - _ghostView.SetScaleTransitionDuration(PickupDuration); - _candidateScale.Transitions = new Transitions - { - CreateScaleTransition(ScaleTransform.ScaleXProperty, PickupDuration), - CreateScaleTransition(ScaleTransform.ScaleYProperty, PickupDuration) - }; - _candidateOutline.Transitions = new Transitions - { - CreateOpacityTransition(PickupDuration) - }; + _root.Transitions = new Transitions + { + CreateOpacityTransition(PickupDuration) + }; + _ghostView.SetOpacityTransitionDuration(PickupDuration); + _ghostView.SetScaleTransitionDuration(PickupDuration); + _candidateScale.Transitions = new Transitions + { + CreateScaleTransition(ScaleTransform.ScaleXProperty, PickupDuration), + CreateScaleTransition(ScaleTransform.ScaleYProperty, PickupDuration) + }; + _candidateOutline.Transitions = new Transitions + { + CreateOpacityTransition(PickupDuration) + }; + } _ghostView.SetRestingScale(initialGhostScale); _candidateOutline.Opacity = 0; _candidateScale.ScaleX = 0.97; @@ -243,21 +244,24 @@ internal sealed class DesktopEditOverlayPresenter var version = ++_dismissVersion; _isVisible = false; var settleDuration = isCancel ? CancelSettleDuration : CommitSettleDuration; - _root.Transitions = new Transitions + if (DesktopEditAnimationRuntime.CanUseTransitions()) { - CreateOpacityTransition(settleDuration) - }; - _ghostView.SetOpacityTransitionDuration(settleDuration); - _ghostView.SetScaleTransitionDuration(settleDuration); - _candidateScale.Transitions = new Transitions - { - CreateScaleTransition(ScaleTransform.ScaleXProperty, settleDuration), - CreateScaleTransition(ScaleTransform.ScaleYProperty, settleDuration) - }; - _candidateOutline.Transitions = new Transitions - { - CreateOpacityTransition(settleDuration) - }; + _root.Transitions = new Transitions + { + CreateOpacityTransition(settleDuration) + }; + _ghostView.SetOpacityTransitionDuration(settleDuration); + _ghostView.SetScaleTransitionDuration(settleDuration); + _candidateScale.Transitions = new Transitions + { + CreateScaleTransition(ScaleTransform.ScaleXProperty, settleDuration), + CreateScaleTransition(ScaleTransform.ScaleYProperty, settleDuration) + }; + _candidateOutline.Transitions = new Transitions + { + CreateOpacityTransition(settleDuration) + }; + } var targetScale = _ghostView.HasPreviewImage ? 1.00 : isCancel ? 0.96 : 1.04; @@ -292,7 +296,7 @@ internal sealed class DesktopEditOverlayPresenter var rect = _previewRect.Value; _ghostView.Width = Math.Max(1, rect.Width); _ghostView.Height = Math.Max(1, rect.Height); - SetOverlayOffset(_ghostView, new Point(rect.X, rect.Y), ref _ghostUsesCompositionOffset); + SetOverlayOffset(_ghostView, new Point(rect.X, rect.Y)); _ghostView.UpdatePreviewMetrics(rect.Width, rect.Height); } @@ -309,7 +313,7 @@ internal sealed class DesktopEditOverlayPresenter _candidateOutline.IsVisible = true; _candidateOutline.Width = Math.Max(1, rect.Width); _candidateOutline.Height = Math.Max(1, rect.Height); - SetOverlayOffset(_candidateOutline, new Point(rect.X, rect.Y), ref _candidateUsesCompositionOffset); + SetOverlayOffset(_candidateOutline, new Point(rect.X, rect.Y)); var cornerRadius = Math.Clamp(Math.Min(rect.Width, rect.Height) * 0.11, 14, 26); _candidateOutline.CornerRadius = new CornerRadius(cornerRadius); @@ -339,24 +343,11 @@ internal sealed class DesktopEditOverlayPresenter return new Rect(rect.X, rect.Y, width, height); } - private void SetOverlayOffset(Control target, Point position, ref bool usesCompositionOffset) + private void SetOverlayOffset(Control target, Point position) { - if (_visualAnimationService.TrySetOffset(target, position)) - { - Canvas.SetLeft(target, 0); - Canvas.SetTop(target, 0); - usesCompositionOffset = true; - return; - } - - if (usesCompositionOffset) - { - _visualAnimationService.TryResetOffset(target); - usesCompositionOffset = false; - } - Canvas.SetLeft(target, position.X); Canvas.SetTop(target, position.Y); + _visualAnimationService.TryResetOffset(target); } private static DoubleTransition CreateScaleTransition(AvaloniaProperty property, TimeSpan duration) =>