Browse Source

[Avalonia] Refactor, update packages, misc

Ruben 1 year ago
parent
commit
87a1f0bb72

+ 2 - 2
src/PicView.Avalonia.MacOS/PicView.Avalonia.MacOS.csproj

@@ -17,8 +17,8 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Avalonia.Desktop" Version="11.1.0-beta2" />
-    <PackageReference Include="Avalonia.Themes.Simple" Version="11.1.0-beta2" />
+    <PackageReference Include="Avalonia.Desktop" Version="11.1.0-rc1" />
+    <PackageReference Include="Avalonia.Themes.Simple" Version="11.1.0-rc1" />
   </ItemGroup>
 
   <ItemGroup>

+ 2 - 2
src/PicView.Avalonia.Win32/PicView.Avalonia.Win32.csproj

@@ -33,8 +33,8 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="Avalonia.Desktop" Version="11.1.0-beta2" />
-    <PackageReference Include="Avalonia.Themes.Simple" Version="11.1.0-beta2" />
+    <PackageReference Include="Avalonia.Desktop" Version="11.1.0-rc1" />
+    <PackageReference Include="Avalonia.Themes.Simple" Version="11.1.0-rc1" />
   </ItemGroup>
 
   <ItemGroup>

+ 0 - 11
src/PicView.Avalonia/CustomControls/AdvancedImageBox.cs

@@ -1,11 +0,0 @@
-using Avalonia;
-using Avalonia.Controls.Primitives;
-
-namespace PicView.Avalonia.CustomControls;
-
-public class AdvancedImageBox : TemplatedControl, IScrollable
-{
-    public Size Extent { get; }
-    public Vector Offset { get; set; }
-    public Size Viewport { get; }
-}

+ 130 - 0
src/PicView.Avalonia/CustomControls/PicBox.cs

@@ -0,0 +1,130 @@
+using Avalonia;
+using Avalonia.Automation;
+using Avalonia.Automation.Peers;
+using Avalonia.Controls;
+using Avalonia.Controls.Automation.Peers;
+using Avalonia.Controls.Primitives;
+using Avalonia.Media;
+using Avalonia.Metadata;
+using PicView.Avalonia.Navigation;
+using PicView.Core.Config;
+
+namespace PicView.Avalonia.CustomControls;
+
+public class PicBox : Control
+{
+    /// <summary>
+    /// Defines the <see cref="Source"/> property.
+    /// </summary>
+    public static readonly StyledProperty<IImage?> SourceProperty =
+        AvaloniaProperty.Register<Image, IImage?>(nameof(Source));
+    
+    /// <summary>
+    /// Gets or sets the image that will be displayed.
+    /// </summary>
+    [Content]
+    public IImage? Source
+    {
+        get => GetValue(SourceProperty);
+        set => SetValue(SourceProperty, value);
+    }
+    
+    public static readonly AvaloniaProperty<ImageType> ImageTypeProperty =
+        AvaloniaProperty.Register<AnimatedMenu, ImageType>(nameof(ImageType));
+
+    public ImageType ImageType
+    {
+        get => (ImageType)(GetValue(ImageTypeProperty) ?? false);
+        set => SetValue(ImageTypeProperty, value);
+    }
+    
+    
+    static PicBox()
+    {
+        AutomationProperties.ControlTypeOverrideProperty.OverrideDefaultValue<PicBox>(AutomationControlType.Image);
+    }
+    
+    #region Rendering
+    
+    /// <summary>
+    /// Renders the control.
+    /// </summary>
+    /// <param name="context">The drawing context.</param>
+    public sealed override void Render(DrawingContext context)
+    {
+        base.Render(context);
+        var source = Source;
+
+        if (source == null || Bounds is not { Width: > 0, Height: > 0 })
+        {
+            return;
+        }
+
+        var viewPort = new Rect(Bounds.Size);
+        var sourceSize = source.Size;
+        
+        var scaleX = 1.0;
+        var scaleY = 1.0;
+        var scale = 1;
+        var scaledSize = sourceSize * scale;
+        var destRect = viewPort
+            .CenterRect(new Rect(scaledSize))
+            .Intersect(viewPort);
+        var sourceRect = new Rect(sourceSize)
+            .CenterRect(new Rect(destRect.Size / scale));
+
+        // var isConstrainedWidth = !double.IsPositiveInfinity(viewPort.Width);
+        // var isConstrainedHeight = !double.IsPositiveInfinity(viewPort.Height);
+        //
+        // Vector scale = Stretch.CalculateScaling(Bounds.Size, sourceSize, StretchDirection);
+        // Size scaledSize = sourceSize * scale;
+        // Rect destRect = viewPort
+        //     .CenterRect(new Rect(scaledSize))
+        //     .Intersect(viewPort);
+        // Rect sourceRect = new Rect(sourceSize)
+        //     .CenterRect(new Rect(destRect.Size / scale));
+        
+        // if (SettingsHelper.Settings.ImageScaling.StretchImage)
+        // {
+        //     UniformToFill(panelWidth, panelHeight, elementWidth, elementHeight, skipTransitions);
+        // }
+        // else
+        // {
+        //     Uniform(panelWidth, panelHeight, elementWidth, elementHeight, skipTransitions);
+        // }
+
+        if (SettingsHelper.Settings.ImageScaling.StretchImage)
+        {
+            context.DrawImage(source, sourceRect, destRect);
+        }
+        else
+        {
+            context.DrawImage(source, sourceRect, destRect);
+        }
+        
+    }
+    
+    /*private void Invalidate(bool skipTransitions = false)
+    {
+        InvalidateProperties();
+        InvalidateScrollable();
+        InvalidateElement(skipTransitions);
+        RaiseZoomChanged();
+    }
+    
+    private void InvalidateProperties()
+    {
+        SetAndRaise(ZoomXProperty, ref _zoomX, _matrix.M11);
+        SetAndRaise(ZoomYProperty, ref _zoomY, _matrix.M22);
+        SetAndRaise(OffsetXProperty, ref _offsetX, _matrix.M31);
+        SetAndRaise(OffsetYProperty, ref _offsetY, _matrix.M32);
+    }*/
+    
+    #endregion
+    
+    protected override AutomationPeer OnCreateAutomationPeer()
+    {
+        return new ImageAutomationPeer(this);
+    }
+
+}

+ 71 - 3
src/PicView.Avalonia/Helpers/AnimationsHelper.cs

@@ -82,9 +82,67 @@ public static class AnimationsHelper
         };
     }
     
+    public static Animation RotationAnimation(object from, object to, double speed)
+    {
+        return new Animation
+        {
+            Duration = TimeSpan.FromSeconds(speed),
+            Easing = new LinearEasing(),
+            FillMode = FillMode.Forward,
+            Children =
+            {
+                new KeyFrame
+                {
+                    Setters =
+                    {
+                        new Setter
+                        {
+                            Property = RotateTransform.AngleProperty,
+                            Value = from
+                        },
+                        new Setter
+                        {
+                            Property = RotateTransform.CenterXProperty,
+                            Value = from
+                        },
+                        new Setter
+                        {
+                            Property = RotateTransform.CenterYProperty,
+                            Value = from
+                        }
+                    },
+                    Cue = new Cue(0d)
+                },
+                new KeyFrame
+                {
+                    Setters =
+                    {
+                        new Setter
+                        {
+                            Property = RotateTransform.AngleProperty,
+                            Value = to
+                        },
+                        new Setter
+                        {
+                            Property = RotateTransform.CenterXProperty,
+                            Value = to
+                        },
+                        new Setter
+                        {
+                            Property = RotateTransform.CenterYProperty,
+                            Value = to
+                        }
+                    },
+                    Cue = new Cue(1d)
+                },
+            }
+        };
+    }
+    
     public static Animation FlipAnimation(object from, object to, double speed)
     {
-        var scale = ScaleTransform.ScaleXProperty;
+        var x = ScaleTransform.ScaleXProperty;
+        var y = ScaleTransform.ScaleYProperty;
         return new Animation
         {
             Duration = TimeSpan.FromSeconds(speed),
@@ -98,8 +156,13 @@ public static class AnimationsHelper
                     {
                         new Setter
                         {
-                            Property = scale,
+                            Property = x,
                             Value = from
+                        },
+                        new Setter
+                        {
+                            Property = y,
+                            Value = 1
                         }
                     },
                     Cue = new Cue(0d)
@@ -110,8 +173,13 @@ public static class AnimationsHelper
                     {
                         new Setter
                         {
-                            Property = scale,
+                            Property = x,
                             Value = to
+                        },
+                        new Setter
+                        {
+                            Property = y,
+                            Value = 1
                         }
                     },
                     Cue = new Cue(1d)

+ 19 - 26
src/PicView.Avalonia/Helpers/FunctionsHelper.cs

@@ -241,59 +241,52 @@ public static class FunctionsHelper
 
         if (Vm.IsScrollingEnabled)
         {
-            await Dispatcher.UIThread.InvokeAsync(() =>
+            if (Vm.ImageViewer.ImageScrollViewer.Offset.Y == 0)
             {
-                if (Vm.ImageViewer.ImageScrollViewer.Offset.Y == 0)
-                {
-                    Vm.ImageViewer.Rotate(clockWise: true, animate: true);
-                }
-                else
+               Vm.ImageViewer.Rotate(clockWise: true, animate: true);
+            }
+            else
+            {
+                await Dispatcher.UIThread.InvokeAsync(() =>
                 {
                     Vm.ImageViewer.ImageScrollViewer.LineUp();
-                }
-            });
+                });
+            }
         }
         else
         {
-            await Dispatcher.UIThread.InvokeAsync(() =>
-            {
-                Vm.ImageViewer.Rotate(clockWise: true, animate: true);
-            });
+            Vm.ImageViewer.Rotate(clockWise: true, animate: true);
         }
     }
 
-    public static async Task RotateRight()
+    public static Task RotateRight()
     {
         if (Vm is null)
         {
-            return;
+            return Task.CompletedTask;
         }
 
         if (GalleryFunctions.IsFullGalleryOpen)
         {
-            return;
+            return Task.CompletedTask;
         }
-        await Dispatcher.UIThread.InvokeAsync(() =>
-        {
-            Vm.ImageViewer.Rotate(clockWise: true, animate: true);
-        });
+        Vm.ImageViewer.Rotate(clockWise: true, animate: true);
+        return Task.CompletedTask;
     }
 
-    public static async Task RotateLeft()
+    public static Task RotateLeft()
     {
         if (Vm is null)
         {
-            return;
+            return Task.CompletedTask;
         }
 
         if (GalleryFunctions.IsFullGalleryOpen)
         {
-            return;
+            return Task.CompletedTask;
         }
-        await Dispatcher.UIThread.InvokeAsync(() =>
-        {
-            Vm.ImageViewer.Rotate(clockWise: false, animate: true);
-        });
+        Vm.ImageViewer.Rotate(clockWise: false, animate: true);
+        return Task.CompletedTask;
     }
 
     public static async Task Down()

+ 32 - 4
src/PicView.Avalonia/Navigation/ImageIterator.cs

@@ -364,7 +364,7 @@ public class ImageIterator
                 {
                     if (showThumb)
                     {
-                        await NavigationHelper.LoadingPreview(index, vm);
+                        await LoadingPreview(index, vm);
                         if (Index != index)
                         {
                             return;
@@ -381,7 +381,7 @@ public class ImageIterator
             }
             else
             {
-                await NavigationHelper.LoadingPreview(index, vm);
+                await LoadingPreview(index, vm);
                 var added = await PreLoader.AddAsync(index, Pics);
                 if (Index != index)
                 {
@@ -528,7 +528,7 @@ public class ImageIterator
 
                 if (preLoadValue.IsLoading)
                 {
-                    await NavigationHelper.LoadingPreview(index, vm);
+                    await LoadingPreview(index, vm);
                 }
 
                 var x = 0;
@@ -545,7 +545,7 @@ public class ImageIterator
         }
         else
         {
-            await NavigationHelper.LoadingPreview(index, vm);
+            await LoadingPreview(index, vm);
             await PreLoader.AddAsync(index, Pics).ConfigureAwait(false);
             preLoadValue = PreLoader.Get(index, Pics);
             if (preLoadValue is null)
@@ -574,4 +574,32 @@ public class ImageIterator
         await AddAsync(Index, preLoadValue.ImageModel);
         await Preload();
     }
+    
+    public async Task LoadingPreview(int index, MainViewModel vm)
+    {
+        if (index != Index)
+        {
+            return;
+        }
+        vm.SetLoadingTitle();
+        vm.SelectedGalleryItemIndex = index;
+        using var image = new MagickImage();
+        image.Ping(vm.ImageIterator.Pics[index]);
+        var thumb = image.GetExifProfile()?.CreateThumbnail();
+        if (thumb is null && index == Index)
+        {
+            vm.IsLoading = true;
+            await Dispatcher.UIThread.InvokeAsync(() =>  vm.ImageViewer.MainImage.Source = null);
+            return;
+        }
+
+        var byteArray = await Task.FromResult(thumb.ToByteArray());
+        var stream = new MemoryStream(byteArray);
+        if (index != Index)
+        {
+            return;
+        }
+        vm.ImageViewer.SetImage(new Bitmap(stream), ImageType.Bitmap);
+        WindowHelper.SetSize(image.Width, image.Height, 0, vm);
+    }
 }

+ 0 - 20
src/PicView.Avalonia/Navigation/NavigationHelper.cs

@@ -139,26 +139,6 @@ public static class NavigationHelper
             await vm.ImageIterator.LoadPicFromString(source, vm).ConfigureAwait(false);
         }
     }
-
-    public static async Task LoadingPreview(int index, MainViewModel vm)
-    {
-        vm.SetLoadingTitle();
-        vm.SelectedGalleryItemIndex = index;
-        using var image = new MagickImage();
-        image.Ping(vm.ImageIterator.Pics[index]);
-        var thumb = image.GetExifProfile()?.CreateThumbnail();
-        if (thumb is null)
-        {
-            vm.IsLoading = true;
-            await Dispatcher.UIThread.InvokeAsync(() =>  vm.ImageViewer.MainImage.Source = null);
-            return;
-        }
-
-        var byteArray = await Task.FromResult(thumb.ToByteArray());
-        var stream = new MemoryStream(byteArray);
-        vm.ImageViewer.SetImage(new Bitmap(stream), ImageType.Bitmap);
-        WindowHelper.SetSize(image.Width, image.Height, 0, vm);
-    }
     
     public static async Task GoToNextFolder(bool next, MainViewModel vm)
     {

+ 3 - 3
src/PicView.Avalonia/PicView.Avalonia.csproj

@@ -51,10 +51,10 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="Avalonia" Version="11.1.0-beta2" />
-    <PackageReference Include="Avalonia.ReactiveUI" Version="11.1.0-beta2" />
+    <PackageReference Include="Avalonia" Version="11.1.0-rc1" />
+    <PackageReference Include="Avalonia.ReactiveUI" Version="11.1.0-rc1" />
     <!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
-    <PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.1.0-beta2" />
+    <PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.1.0-rc1" />
     <PackageReference Include="Avalonia.Svg.Skia" Version="11.1.0-beta1" />
     <PackageReference Include="Magick.NET-Q8-OpenMP-x64" Version="13.9.1" />
   </ItemGroup>

+ 15 - 8
src/PicView.Avalonia/Views/UC/ToolTipMessage.axaml.cs

@@ -15,7 +15,7 @@ public partial class ToolTipMessage : UserControl
 
         // Subscribe to the ToolTipMessageText.Text changes
         this.WhenAnyValue(x => x.ToolTipMessageText.Text)
-            .Throttle(TimeSpan.FromMilliseconds(500)) // Avoid rapid consecutive changes
+            .Throttle(TimeSpan.FromMilliseconds(100)) // Avoid rapid consecutive changes
             .Where(text => !string.IsNullOrEmpty(text))
             .ObserveOn(RxApp.MainThreadScheduler)
             .Select(async _ =>
@@ -27,18 +27,25 @@ public partial class ToolTipMessage : UserControl
 
     private async Task DoAnimation()
     {
+        if (_isRunning)
+        {
+            return;
+        }
+
+        _isRunning = true;
+
         // ReSharper disable once CompareOfFloatsByEqualityOperator
-        if (Opacity < .2)
+        if (Opacity != 1)
         {
-            var fadeInAnimation = AnimationsHelper.OpacityAnimation(from: Opacity, to: 1, 1.5);
+            var fadeInAnimation = AnimationsHelper.OpacityAnimation(from: 0, to: 1, 1.5);
             await fadeInAnimation.RunAsync(this);
         }
+
+        // Wait for the duration before fading out
         await Task.Delay(TimeSpan.FromSeconds(1.5));
-        if (!_isRunning)
-        {
-            var fadeOutAnimation = AnimationsHelper.OpacityAnimation(from: Opacity, to: 0, 1.5);
-            await fadeOutAnimation.RunAsync(this);
-        }
         _isRunning = false;
+        
+        var fadeOutAnimation = AnimationsHelper.OpacityAnimation(from: 1, to: 0, 1.5);
+        await fadeOutAnimation.RunAsync(this);
     }
 }

+ 1 - 1
src/PicView.Core/Gallery/GalleryThumbInfo.cs

@@ -91,7 +91,7 @@ public class GalleryThumbInfo
         /// <param name="imageSource">The image source of the thumbnail.</param>
         /// <param name="fileInfo">The file information of the thumbnail.</param>
         /// <returns>The <see cref="GalleryThumbHolder"/> instance containing thumbnail data.</returns>
-        public static GalleryThumbHolder GetThumbData(int index, IImageSource? imageSource, FileInfo fileInfo)
+        public static GalleryThumbHolder GetThumbData(int index, IImageSource? imageSource, FileInfo? fileInfo)
         {
             const int fileNameLength = 60;
             var fileLocation = fileInfo.FullName;

+ 1 - 1
src/PicView.Tests/PicView.Tests.csproj

@@ -10,7 +10,7 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Avalonia.Headless.XUnit" Version="11.1.0-beta2" />
+    <PackageReference Include="Avalonia.Headless.XUnit" Version="11.1.0-rc1" />
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
     <PackageReference Include="xunit" Version="2.8.1" />
     <PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">