浏览代码

Add resize windows, refactor, misc. fixes and more.

Ruben 1 年之前
父节点
当前提交
fa043f6427
共有 26 个文件被更改,包括 567 次插入68 次删除
  1. 6 1
      src/PicView.Avalonia.MacOS/App.axaml.cs
  2. 69 2
      src/PicView.Avalonia.Win32/App.axaml.cs
  3. 4 0
      src/PicView.Avalonia.Win32/PicView.Avalonia.Win32.csproj
  4. 101 0
      src/PicView.Avalonia.Win32/Views/BatchResizeResizeWindow.axaml
  5. 86 0
      src/PicView.Avalonia.Win32/Views/BatchResizeResizeWindow.axaml.cs
  6. 101 0
      src/PicView.Avalonia.Win32/Views/SingleImageResizeWindow.axaml
  7. 86 0
      src/PicView.Avalonia.Win32/Views/SingleImageResizeWindow.axaml.cs
  8. 1 0
      src/PicView.Avalonia.Win32/Views/WinMainWindow.axaml.cs
  9. 1 1
      src/PicView.Avalonia.Win32/Views/WinTitleBar.axaml.cs
  10. 14 28
      src/PicView.Avalonia/CustomControls/PicBox.cs
  11. 2 1
      src/PicView.Avalonia/DragAndDrop/DragAndDropHelper.cs
  12. 3 1
      src/PicView.Avalonia/Interfaces/IPlatformSpecificService.cs
  13. 10 23
      src/PicView.Avalonia/Navigation/ImageIterator.cs
  14. 5 0
      src/PicView.Avalonia/Navigation/UpdateImage.cs
  15. 5 0
      src/PicView.Avalonia/PicView.Avalonia.csproj
  16. 1 1
      src/PicView.Avalonia/UI/FunctionsHelper.cs
  17. 4 2
      src/PicView.Avalonia/ViewModels/MainViewModel.cs
  18. 16 0
      src/PicView.Avalonia/Views/BatchResizeView.axaml
  19. 12 0
      src/PicView.Avalonia/Views/BatchResizeView.axaml.cs
  20. 1 1
      src/PicView.Avalonia/Views/BottomBar.axaml.cs
  21. 0 3
      src/PicView.Avalonia/Views/ImageViewer.axaml.cs
  22. 1 2
      src/PicView.Avalonia/Views/MainView.axaml.cs
  23. 25 0
      src/PicView.Avalonia/Views/SingleImageResizeView.axaml
  24. 11 0
      src/PicView.Avalonia/Views/SingleImageResizeView.axaml.cs
  25. 1 1
      src/PicView.Avalonia/Views/UC/Menus/ImageMenu.axaml
  26. 1 1
      src/PicView.Avalonia/Views/UC/Menus/ToolsMenu.axaml

+ 6 - 1
src/PicView.Avalonia.MacOS/App.axaml.cs

@@ -281,11 +281,16 @@ public void ShowAboutWindow()
         // TODO: Implement ShowEffectsWindow
     }
 
-    public void ShowResizeWindow()
+    public void ShowSingleImageResizeWindow()
     {
         // TODO: Implement ShowResizeWindow
     }
 
+    public void ShowBatchResizeWindow()
+    {
+        // TODO: Implement ShowBatchResizeWindow
+    }
+
     public void Print(string path)
     {
         // TODO: Implement Print

+ 69 - 2
src/PicView.Avalonia.Win32/App.axaml.cs

@@ -30,6 +30,8 @@ public class App : Application, IPlatformSpecificService
     private SettingsWindow? _settingsWindow;
     private KeybindingsWindow? _keybindingsWindow;
     private AboutWindow? _aboutWindow;
+    private SingleImageResizeWindow? _singleImageResizeWindow;
+    private BatchResizeWindow? _batchResizeWindow;
     private MainViewModel? _vm;
     
     private TaskbarProgress? _taskbarProgress;
@@ -306,9 +308,74 @@ public class App : Application, IPlatformSpecificService
         // TODO: Implement ShowEffectsWindow
     }
 
-    public void ShowResizeWindow()
+    public void ShowSingleImageResizeWindow()
     {
-        // TODO: Implement ShowResizeWindow
+        if (Dispatcher.UIThread.CheckAccess())
+        {
+            Set();
+        }
+        else
+        {
+            Dispatcher.UIThread.InvokeAsync(Set);
+        }
+        return;
+        void Set()
+        {
+            if (Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
+            {
+                return;
+            }
+            if (_singleImageResizeWindow is null)
+            {
+                _singleImageResizeWindow = new SingleImageResizeWindow
+                {
+                    DataContext = _vm,
+                    WindowStartupLocation = WindowStartupLocation.CenterOwner,
+                };
+                _singleImageResizeWindow.Show(desktop.MainWindow);
+                _singleImageResizeWindow.Closing += (s, e) => _singleImageResizeWindow = null;
+            }
+            else
+            {
+                _singleImageResizeWindow.Activate();                
+            }
+            _= FunctionsHelper.CloseMenus();
+        }
+    }
+    
+    public void ShowBatchResizeWindow()
+    {
+        if (Dispatcher.UIThread.CheckAccess())
+        {
+            Set();
+        }
+        else
+        {
+            Dispatcher.UIThread.InvokeAsync(Set);
+        }
+        return;
+        void Set()
+        {
+            if (Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
+            {
+                return;
+            }
+            if (_batchResizeWindow is null)
+            {
+                _batchResizeWindow = new BatchResizeWindow
+                {
+                    DataContext = _vm,
+                    WindowStartupLocation = WindowStartupLocation.CenterOwner,
+                };
+                _batchResizeWindow.Show(desktop.MainWindow);
+                _batchResizeWindow.Closing += (s, e) => _batchResizeWindow = null;
+            }
+            else
+            {
+                _batchResizeWindow.Activate();
+            }
+            _= FunctionsHelper.CloseMenus();
+        }   
     }
 
     public void Print(string path)

+ 4 - 0
src/PicView.Avalonia.Win32/PicView.Avalonia.Win32.csproj

@@ -71,6 +71,10 @@
     <Compile Update="Views\WinTitleBar.axaml.cs">
       <DependentUpon>WinTitleBar.axaml</DependentUpon>
     </Compile>
+    <Compile Update="Views\BatchResizeResizeWindow.axaml.cs">
+      <DependentUpon>BatchResizeResizeWindow.axaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
   </ItemGroup>
 
 	<ItemGroup>

+ 101 - 0
src/PicView.Avalonia.Win32/Views/BatchResizeResizeWindow.axaml

@@ -0,0 +1,101 @@
+<Window
+    BorderThickness="1"
+    CanResize="False"
+    CornerRadius="8"
+    SizeToContent="WidthAndHeight"
+    Title="Loading..."
+    d:DesignHeight="450"
+    d:DesignWidth="800"
+    mc:Ignorable="d"
+    x:Class="PicView.Avalonia.Win32.Views.BatchResizeWindow"
+    x:DataType="viewModels:MainViewModel"
+    xmlns="https://github.com/avaloniaui"
+    xmlns:customControls="clr-namespace:PicView.Avalonia.CustomControls;assembly=PicView.Avalonia"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:viewModels="clr-namespace:PicView.Avalonia.ViewModels;assembly=PicView.Avalonia"
+    xmlns:views="clr-namespace:PicView.Avalonia.Views;assembly=PicView.Avalonia"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+    <Design.DataContext>
+        <viewModels:MainViewModel />
+    </Design.DataContext>
+    <Border
+        BorderBrush="{DynamicResource WindowBorderColor}"
+        BorderThickness="1"
+        CornerRadius="8"
+        PointerPressed="MoveWindow"
+        x:Name="ParentBorder">
+        <StackPanel>
+
+            <DockPanel Height="28" LastChildFill="True">
+
+                <Border
+                    Background="{DynamicResource WindowButtonBackgroundColor}"
+                    BorderBrush="{DynamicResource MainBorderColor}"
+                    BorderThickness="0,0,1,0"
+                    CornerRadius="8,0,0,0"
+                    DockPanel.Dock="Left"
+                    x:Name="IconBorder">
+                    <Image
+                        Height="25"
+                        Margin="7,1,7,1"
+                        Source="{StaticResource LogoImage}"
+                        Width="20" />
+                </Border>
+
+                <customControls:IconButton
+                    Background="{DynamicResource WindowButtonBackgroundColor}"
+                    BorderThickness="0"
+                    Classes="hover"
+                    Click="Close"
+                    ClickMode="Release"
+                    CornerRadius="0,8,0,0"
+                    Data="{StaticResource CloseGeometry}"
+                    DockPanel.Dock="Right"
+                    Foreground="{DynamicResource MainTextColor}"
+                    IconHeight="10"
+                    IconWidth="10"
+                    Width="30"
+                    x:Name="CloseButton" />
+
+                <customControls:IconButton
+                    Background="{DynamicResource WindowButtonBackgroundColor}"
+                    BorderBrush="{DynamicResource MainBorderColor}"
+                    BorderThickness="1,0,1,0"
+                    Classes="hover"
+                    Click="Minimize"
+                    Data="{StaticResource MinimizeGeometry}"
+                    DockPanel.Dock="Right"
+                    Foreground="{DynamicResource MainTextColor}"
+                    IconHeight="12"
+                    IconWidth="12"
+                    Width="30"
+                    x:Name="MinimizeButton" />
+
+                <TextBlock
+                    Background="{DynamicResource WindowSecondaryBackgroundColor}"
+                    Classes="txt"
+                    Foreground="{DynamicResource MainTextColor}"
+                    Height="28"
+                    LineHeight="28"
+                    Padding="30,0,0,0"
+                    Text="{CompiledBinding BatchResize,
+                                           Mode=OneWay}"
+                    TextAlignment="Center"
+                    x:Name="TitleText" />
+            </DockPanel>
+
+            <Rectangle
+                Fill="{DynamicResource WindowBorderColor}"
+                Height="1"
+                x:Name="BorderRectangle" />
+
+            <views:BatchResizeView
+                Background="{DynamicResource NoisyTexture}"
+                Focusable="True"
+                Margin="0"
+                Padding="10,2,5,10"
+                PointerPressed="MoveWindow" />
+        </StackPanel>
+    </Border>
+</Window>

+ 86 - 0
src/PicView.Avalonia.Win32/Views/BatchResizeResizeWindow.axaml.cs

@@ -0,0 +1,86 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.Media;
+using PicView.Core.Config;
+using PicView.Core.Localization;
+
+namespace PicView.Avalonia.Win32.Views;
+
+public partial class BatchResizeWindow : Window
+{
+    public BatchResizeWindow()
+    {
+        InitializeComponent();
+        StartUp();
+    }
+
+    private void StartUp()
+    {
+        if (SettingsHelper.Settings.Theme.GlassTheme)
+        {
+            IconBorder.Background = Brushes.Transparent;
+            IconBorder.BorderThickness = new Thickness(0);
+            MinimizeButton.Background = Brushes.Transparent;
+            MinimizeButton.BorderThickness = new Thickness(0);
+            CloseButton.Background = Brushes.Transparent;
+            CloseButton.BorderThickness = new Thickness(0);
+            BorderRectangle.Height = 0;
+            TitleText.Background = Brushes.Transparent;
+
+            if (!Application.Current.TryGetResource("SecondaryTextColor",
+                    Application.Current.RequestedThemeVariant, out var textColor))
+            {
+                return;
+            }
+
+            if (textColor is not Color color)
+            {
+                return;
+            }
+
+            TitleText.Foreground = new SolidColorBrush(color);
+            MinimizeButton.Foreground = new SolidColorBrush(color);
+            CloseButton.Foreground = new SolidColorBrush(color);
+        }
+        else if (!SettingsHelper.Settings.Theme.Dark)
+        {
+            ParentBorder.Background = new SolidColorBrush(Color.FromArgb(114, 132, 132, 132));
+        }
+
+        Loaded += delegate
+        {
+            MinWidth = MaxWidth = Width;
+            Title = $"{TranslationHelper.Translation.BatchResize}  - PicView";
+        };
+        KeyDown += (_, e) =>
+        {
+            if (e.Key is Key.Escape)
+            {
+                Close();
+            }
+        };
+    }
+
+    private void MoveWindow(object? sender, PointerPressedEventArgs e)
+    {
+        if (VisualRoot is null)
+        {
+            return;
+        }
+
+        var hostWindow = (Window)VisualRoot;
+        hostWindow?.BeginMoveDrag(e);
+    }
+
+    private void Close(object? sender, RoutedEventArgs e)
+    {
+        Close();
+    }
+
+    private void Minimize(object? sender, RoutedEventArgs e)
+    {
+        WindowState = WindowState.Minimized;
+    }
+}

+ 101 - 0
src/PicView.Avalonia.Win32/Views/SingleImageResizeWindow.axaml

@@ -0,0 +1,101 @@
+<Window
+    BorderThickness="1"
+    CanResize="False"
+    CornerRadius="8"
+    SizeToContent="WidthAndHeight"
+    Title="Loading..."
+    d:DesignHeight="450"
+    d:DesignWidth="800"
+    mc:Ignorable="d"
+    x:Class="PicView.Avalonia.Win32.Views.SingleImageResizeWindow"
+    x:DataType="viewModels:MainViewModel"
+    xmlns="https://github.com/avaloniaui"
+    xmlns:customControls="clr-namespace:PicView.Avalonia.CustomControls;assembly=PicView.Avalonia"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:viewModels="clr-namespace:PicView.Avalonia.ViewModels;assembly=PicView.Avalonia"
+    xmlns:views="clr-namespace:PicView.Avalonia.Views;assembly=PicView.Avalonia"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+    <Design.DataContext>
+        <viewModels:MainViewModel />
+    </Design.DataContext>
+    <Border
+        BorderBrush="{DynamicResource WindowBorderColor}"
+        BorderThickness="1"
+        CornerRadius="8"
+        PointerPressed="MoveWindow"
+        x:Name="ParentBorder">
+        <StackPanel>
+
+            <DockPanel Height="28" LastChildFill="True">
+
+                <Border
+                    Background="{DynamicResource WindowButtonBackgroundColor}"
+                    BorderBrush="{DynamicResource MainBorderColor}"
+                    BorderThickness="0,0,1,0"
+                    CornerRadius="8,0,0,0"
+                    DockPanel.Dock="Left"
+                    x:Name="IconBorder">
+                    <Image
+                        Height="25"
+                        Margin="7,1,7,1"
+                        Source="{StaticResource LogoImage}"
+                        Width="20" />
+                </Border>
+
+                <customControls:IconButton
+                    Background="{DynamicResource WindowButtonBackgroundColor}"
+                    BorderThickness="0"
+                    Classes="hover"
+                    Click="Close"
+                    ClickMode="Release"
+                    CornerRadius="0,8,0,0"
+                    Data="{StaticResource CloseGeometry}"
+                    DockPanel.Dock="Right"
+                    Foreground="{DynamicResource MainTextColor}"
+                    IconHeight="10"
+                    IconWidth="10"
+                    Width="30"
+                    x:Name="CloseButton" />
+
+                <customControls:IconButton
+                    Background="{DynamicResource WindowButtonBackgroundColor}"
+                    BorderBrush="{DynamicResource MainBorderColor}"
+                    BorderThickness="1,0,1,0"
+                    Classes="hover"
+                    Click="Minimize"
+                    Data="{StaticResource MinimizeGeometry}"
+                    DockPanel.Dock="Right"
+                    Foreground="{DynamicResource MainTextColor}"
+                    IconHeight="12"
+                    IconWidth="12"
+                    Width="30"
+                    x:Name="MinimizeButton" />
+
+                <TextBlock
+                    Background="{DynamicResource WindowSecondaryBackgroundColor}"
+                    Classes="txt"
+                    Foreground="{DynamicResource MainTextColor}"
+                    Height="28"
+                    LineHeight="28"
+                    Padding="30,0,0,0"
+                    Text="{CompiledBinding Resize,
+                                           Mode=OneWay}"
+                    TextAlignment="Center"
+                    x:Name="TitleText" />
+            </DockPanel>
+
+            <Rectangle
+                Fill="{DynamicResource WindowBorderColor}"
+                Height="1"
+                x:Name="BorderRectangle" />
+
+            <views:SingleImageResizeView
+                Background="{DynamicResource NoisyTexture}"
+                Focusable="True"
+                Margin="0"
+                Padding="10,2,5,10"
+                PointerPressed="MoveWindow" />
+        </StackPanel>
+    </Border>
+</Window>

+ 86 - 0
src/PicView.Avalonia.Win32/Views/SingleImageResizeWindow.axaml.cs

@@ -0,0 +1,86 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.Media;
+using PicView.Core.Config;
+using PicView.Core.Localization;
+
+namespace PicView.Avalonia.Win32.Views;
+
+public partial class SingleImageResizeWindow : Window
+{
+    public SingleImageResizeWindow()
+    {
+        InitializeComponent();
+        StartUp();
+    }
+
+    private void StartUp()
+    {
+        if (SettingsHelper.Settings.Theme.GlassTheme)
+        {
+            IconBorder.Background = Brushes.Transparent;
+            IconBorder.BorderThickness = new Thickness(0);
+            MinimizeButton.Background = Brushes.Transparent;
+            MinimizeButton.BorderThickness = new Thickness(0);
+            CloseButton.Background = Brushes.Transparent;
+            CloseButton.BorderThickness = new Thickness(0);
+            BorderRectangle.Height = 0;
+            TitleText.Background = Brushes.Transparent;
+
+            if (!Application.Current.TryGetResource("SecondaryTextColor",
+                    Application.Current.RequestedThemeVariant, out var textColor))
+            {
+                return;
+            }
+
+            if (textColor is not Color color)
+            {
+                return;
+            }
+
+            TitleText.Foreground = new SolidColorBrush(color);
+            MinimizeButton.Foreground = new SolidColorBrush(color);
+            CloseButton.Foreground = new SolidColorBrush(color);
+        }
+        else if (!SettingsHelper.Settings.Theme.Dark)
+        {
+            ParentBorder.Background = new SolidColorBrush(Color.FromArgb(114, 132, 132, 132));
+        }
+
+        Loaded += delegate
+        {
+            MinWidth = MaxWidth = Width;
+            Title = $"{TranslationHelper.Translation.Resize}  - PicView";
+        };
+        KeyDown += (_, e) =>
+        {
+            if (e.Key is Key.Escape)
+            {
+                Close();
+            }
+        };
+    }
+
+    private void MoveWindow(object? sender, PointerPressedEventArgs e)
+    {
+        if (VisualRoot is null)
+        {
+            return;
+        }
+
+        var hostWindow = (Window)VisualRoot;
+        hostWindow?.BeginMoveDrag(e);
+    }
+
+    private void Close(object? sender, RoutedEventArgs e)
+    {
+        Close();
+    }
+
+    private void Minimize(object? sender, RoutedEventArgs e)
+    {
+        WindowState = WindowState.Minimized;
+    }
+}

+ 1 - 0
src/PicView.Avalonia.Win32/Views/WinMainWindow.axaml.cs

@@ -1,6 +1,7 @@
 using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Controls.ApplicationLifetimes;
+using PicView.Avalonia.DragAndDrop;
 using PicView.Avalonia.UI;
 using PicView.Avalonia.ViewModels;
 using PicView.Avalonia.WindowBehavior;

+ 1 - 1
src/PicView.Avalonia.Win32/Views/WinTitleBar.axaml.cs

@@ -2,7 +2,7 @@ using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Input;
 using Avalonia.Media;
-using PicView.Avalonia.UI;
+using PicView.Avalonia.DragAndDrop;
 using PicView.Avalonia.ViewModels;
 using PicView.Avalonia.WindowBehavior;
 using PicView.Core.Config;

+ 14 - 28
src/PicView.Avalonia/CustomControls/PicBox.cs

@@ -31,8 +31,6 @@ public class PicBox : Control
     private IGifInstance? _animInstance;
     public string? InitialAnimatedSource;
     private readonly IDisposable? _imageTypeSubscription;
-
-    private static readonly Lock Lock = new();
     
     /// <summary>
     /// Defines the <see cref="Source"/> property.
@@ -121,30 +119,21 @@ public class PicBox : Control
                 }
                 var svgSource = SvgSource.Load(svg);
                 Source = new SvgImage { Source = svgSource };
-                lock (Lock)
-                {
-                    DestroyVisual();
-                    _animInstance?.Dispose();
-                }
+                DestroyVisual();
+                _animInstance?.Dispose();
                 _stream?.Dispose();
                 break;
             case ImageType.AnimatedGif:
             case ImageType.AnimatedWebp:
                 CreateVisual();
                 Source = Source as Bitmap;
-                lock (Lock)
-                {
-                    _animInstance?.Dispose();
-                }
+                _animInstance?.Dispose();
                 
                 break;
             case ImageType.Bitmap:
                 Source = Source as Bitmap;
-                lock (Lock)
-                {
-                    DestroyVisual();
-                    _animInstance?.Dispose();
-                }
+                DestroyVisual();
+                _animInstance?.Dispose();
                 _stream?.Dispose();
                 break;
             case ImageType.Invalid:
@@ -490,20 +479,17 @@ public class PicBox : Control
 
     private void UpdateAnimationInstance(FileStream fileStream)
     {
-        lock (Lock)
+        _animInstance?.Dispose();
+        if (ImageType == ImageType.AnimatedGif)
         {
-            _animInstance?.Dispose();
-            if (ImageType == ImageType.AnimatedGif)
-            {
-                _animInstance = new GifInstance(fileStream);
-            }
-            else
-            {
-                _animInstance = new WebpInstance(fileStream);
-            }
-            _animInstance.IterationCount = IterationCount.Infinite;
-            _customVisual?.SendHandlerMessage(_animInstance);
+            _animInstance = new GifInstance(fileStream);
+        }
+        else
+        {
+            _animInstance = new WebpInstance(fileStream);
         }
+        _animInstance.IterationCount = IterationCount.Infinite;
+        _customVisual?.SendHandlerMessage(_animInstance);
         AnimationUpdate();
     }
     

+ 2 - 1
src/PicView.Avalonia/UI/DragAndDropHelper.cs → src/PicView.Avalonia/DragAndDrop/DragAndDropHelper.cs

@@ -6,6 +6,7 @@ using Avalonia.Platform.Storage;
 using Avalonia.Threading;
 using PicView.Avalonia.ImageHandling;
 using PicView.Avalonia.Navigation;
+using PicView.Avalonia.UI;
 using PicView.Avalonia.ViewModels;
 using PicView.Avalonia.Views.UC;
 using PicView.Core.Calculations;
@@ -13,7 +14,7 @@ using PicView.Core.Config;
 using PicView.Core.FileHandling;
 using PicView.Core.ProcessHandling;
 
-namespace PicView.Avalonia.UI;
+namespace PicView.Avalonia.DragAndDrop;
 
 public static class DragAndDropHelper
 {

+ 3 - 1
src/PicView.Avalonia/Interfaces/IPlatformSpecificService.cs

@@ -29,7 +29,9 @@ public interface IPlatformSpecificService
     
     void ShowEffectsWindow();
     
-    void ShowResizeWindow();
+    void ShowSingleImageResizeWindow();
+    
+    void ShowBatchResizeWindow();
     
     void Print(string path);
     

+ 10 - 23
src/PicView.Avalonia/Navigation/ImageIterator.cs

@@ -30,7 +30,6 @@ public sealed class ImageIterator : IDisposable
     private static FileSystemWatcher? _watcher;
     private static bool _isRunning;
     private readonly MainViewModel? _vm;
-    private readonly Lock _lock = new();
 
     #endregion
 
@@ -501,10 +500,7 @@ public sealed class ImageIterator : IDisposable
         {
             try
             {
-                lock (_lock)
-                {
-                    CurrentIndex = index;
-                }
+                CurrentIndex = index;
 
                 // ReSharper disable once MethodHasAsyncOverload
                 var preloadValue = PreLoader.Get(index, ImagePaths);
@@ -518,13 +514,10 @@ public sealed class ImageIterator : IDisposable
                     while (preloadValue.IsLoading)
                     {
                         await Task.Delay(20).ConfigureAwait(false);
-                        lock (_lock)
+                        if (CurrentIndex != index)
                         {
-                            if (CurrentIndex != index)
-                            {
-                                // Skip loading if user went to next value
-                                return;
-                            }
+                            // Skip loading if user went to next value
+                            return;
                         }
                     }
                 }
@@ -534,26 +527,20 @@ public sealed class ImageIterator : IDisposable
                     preloadValue = await PreLoader.GetAsync(CurrentIndex, ImagePaths).ConfigureAwait(false);
                 }
 
-                lock (_lock)
+                if (CurrentIndex != index)
                 {
-                    if (CurrentIndex != index)
-                    {
-                        // Skip loading if user went to next value
-                        return;
-                    }
+                    // Skip loading if user went to next value
+                    return;
                 }
 
                 if (SettingsHelper.Settings.ImageScaling.ShowImageSideBySide)
                 {
                     var nextIndex = GetIteration(index, IsReversed ? NavigateTo.Previous : NavigateTo.Next);
                     var nextPreloadValue = await PreLoader.GetAsync(nextIndex, ImagePaths);
-                    lock (_lock)
+                    if (CurrentIndex != index)
                     {
-                        if (CurrentIndex != index)
-                        {
-                            // Skip loading if user went to next value
-                            return;
-                        }
+                        // Skip loading if user went to next value
+                        return;
                     }
 
                     if (nextPreloadValue is not null)

+ 5 - 0
src/PicView.Avalonia/Navigation/UpdateImage.cs

@@ -40,6 +40,11 @@ public static class UpdateImage
                 nextPreloadValue.ImageModel = await GetImageModel.GetImageModelAsync(fileInfo).ConfigureAwait(false);
             }
         }
+        
+        if (index != vm.ImageIterator.CurrentIndex)
+        {
+            return;
+        }
 
         await Dispatcher.UIThread.InvokeAsync(() =>
         {

+ 5 - 0
src/PicView.Avalonia/PicView.Avalonia.csproj

@@ -80,6 +80,10 @@
       <DependentUpon>ZoomSettingsView.axaml</DependentUpon>
       <SubType>Code</SubType>
     </Compile>
+    <Compile Update="Views\SingleImageResizeView.axaml.cs">
+      <DependentUpon>SingleImageResizeView.axaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
   </ItemGroup>
 
   
@@ -145,6 +149,7 @@
 
   <ItemGroup>
     <Folder Include="Assets\" />
+    <Folder Include="Resizing\" />
   </ItemGroup>
 
   <ItemGroup>

+ 1 - 1
src/PicView.Avalonia/UI/FunctionsHelper.cs

@@ -494,7 +494,7 @@ public static class FunctionsHelper
 
     public static Task ResizeWindow()
     {
-        Vm?.PlatformService?.ShowResizeWindow();
+        Vm?.PlatformService?.ShowSingleImageResizeWindow();
         return Task.CompletedTask;
     }
 

+ 4 - 2
src/PicView.Avalonia/ViewModels/MainViewModel.cs

@@ -468,7 +468,8 @@ public class MainViewModel : ViewModelBase
     public ReactiveCommand<Unit, Unit>? ShowAboutWindowCommand { get; }
     public ReactiveCommand<Unit, Unit>? ShowSettingsWindowCommand { get; }
     public ReactiveCommand<Unit, Unit>? ShowKeybindingsWindowCommand { get; }
-
+    public ReactiveCommand<Unit, Unit>? ShowBatchResizeWindowCommand { get; }
+    public ReactiveCommand<Unit, Unit>? ShowSingleImageResizeWindowCommand { get; }
     public ReactiveCommand<Unit, Unit>? SetExifRating0Command { get; }
     public ReactiveCommand<Unit, Unit>? SetExifRating1Command { get; }
     public ReactiveCommand<Unit, Unit>? SetExifRating2Command { get; }
@@ -1754,7 +1755,8 @@ public class MainViewModel : ViewModelBase
         ShowSettingsWindowCommand = ReactiveCommand.Create(platformSpecificService.ShowSettingsWindow);
         ShowKeybindingsWindowCommand = ReactiveCommand.Create(platformSpecificService.ShowKeybindingsWindow);
         ShowAboutWindowCommand = ReactiveCommand.Create(platformSpecificService.ShowAboutWindow);
-
+        ShowBatchResizeWindowCommand = ReactiveCommand.Create(platformSpecificService.ShowBatchResizeWindow);
+        ShowSingleImageResizeWindowCommand = ReactiveCommand.Create(platformSpecificService.ShowSingleImageResizeWindow);
         #endregion Window commands
 
         #region Navigation Commands

+ 16 - 0
src/PicView.Avalonia/Views/BatchResizeView.axaml

@@ -0,0 +1,16 @@
+<UserControl
+    d:DesignHeight="450"
+    d:DesignWidth="800"
+    mc:Ignorable="d"
+    x:Class="PicView.Avalonia.Views.BatchResizeView"
+    x:DataType="viewModels:MainViewModel"
+    xmlns="https://github.com/avaloniaui"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:viewModels="clr-namespace:PicView.Avalonia.ViewModels;assembly=PicView.Avalonia"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+    <TabControl>
+        <TabItem Header="{CompiledBinding BatchResize}" />
+        <TabItem Header="Single Image" />
+    </TabControl>
+</UserControl>

+ 12 - 0
src/PicView.Avalonia/Views/BatchResizeView.axaml.cs

@@ -0,0 +1,12 @@
+using Avalonia.Controls;
+
+namespace PicView.Avalonia.Views
+{
+    public partial class BatchResizeView : UserControl
+    {
+        public BatchResizeView()
+        {
+            InitializeComponent();
+        }
+    }
+}

+ 1 - 1
src/PicView.Avalonia/Views/BottomBar.axaml.cs

@@ -2,7 +2,7 @@ using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Input;
 using Avalonia.Media;
-using PicView.Avalonia.UI;
+using PicView.Avalonia.DragAndDrop;
 using PicView.Avalonia.WindowBehavior;
 using PicView.Core.Config;
 

+ 0 - 3
src/PicView.Avalonia/Views/ImageViewer.axaml.cs

@@ -361,9 +361,6 @@ public partial class ImageViewer : UserControl
 
     public void Reset()
     {
-        if (DataContext is not MainViewModel vm)
-            return;
-        
         if (Dispatcher.UIThread.CheckAccess())
         {
             DoReset();

+ 1 - 2
src/PicView.Avalonia/Views/MainView.axaml.cs

@@ -4,11 +4,11 @@ using Avalonia.Controls;
 using Avalonia.Input;
 using Avalonia.Interactivity;
 using Avalonia.Media;
+using PicView.Avalonia.DragAndDrop;
 using PicView.Avalonia.Keybindings;
 using PicView.Avalonia.Navigation;
 using PicView.Avalonia.UI;
 using PicView.Avalonia.ViewModels;
-using PicView.Avalonia.Views.UC;
 using PicView.Avalonia.WindowBehavior;
 using PicView.Core.Config;
 using PicView.Core.Extensions;
@@ -17,7 +17,6 @@ namespace PicView.Avalonia.Views;
 
 public partial class MainView : UserControl
 {
-    private DragDropView? _dragDropView;
     public MainView()
     {
         InitializeComponent();

+ 25 - 0
src/PicView.Avalonia/Views/SingleImageResizeView.axaml

@@ -0,0 +1,25 @@
+<UserControl
+    ZIndex="99"
+    d:DesignHeight="450"
+    d:DesignWidth="800"
+    mc:Ignorable="d"
+    x:Class="PicView.Avalonia.Views.SingleImageResizeView"
+    x:DataType="viewModels:MainViewModel"
+    xmlns="https://github.com/avaloniaui"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:viewModels="clr-namespace:PicView.Avalonia.ViewModels;assembly=PicView.Avalonia"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+    <Panel>
+        <Border
+            BorderBrush="{DynamicResource MainBorderColor}"
+            BorderThickness="1"
+            CornerRadius="8"
+            Height="300"
+            HorizontalAlignment="Center"
+            VerticalAlignment="Center"
+            Width="300">
+            <Image Source="{CompiledBinding ImageSource}" x:Name="ImagePreview" />
+        </Border>
+    </Panel>
+</UserControl>

+ 11 - 0
src/PicView.Avalonia/Views/SingleImageResizeView.axaml.cs

@@ -0,0 +1,11 @@
+using Avalonia.Controls;
+
+namespace PicView.Avalonia.Views;
+
+public partial class SingleImageResizeView : UserControl
+{
+    public SingleImageResizeView()
+    {
+        InitializeComponent();
+    }
+}

+ 1 - 1
src/PicView.Avalonia/Views/UC/Menus/ImageMenu.axaml

@@ -186,8 +186,8 @@
                     Canvas.Left="7"
                     Canvas.Top="53"
                     Classes="ButtonBorder altHover"
+                    Command="{CompiledBinding ShowSingleImageResizeWindowCommand}"
                     Height="46"
-                    IsEnabled="False"
                     ToolTip.Tip="{CompiledBinding ResizeImage,
                                                   Mode=OneWay}">
                     <StackPanel Orientation="Horizontal">

+ 1 - 1
src/PicView.Avalonia/Views/UC/Menus/ToolsMenu.axaml

@@ -45,9 +45,9 @@
                     BorderBrush="{DynamicResource MainBorderColor}"
                     BorderThickness="0,0,1,0"
                     Classes="altHover"
+                    Command="{CompiledBinding ShowBatchResizeWindowCommand}"
                     CornerRadius="8,0,0,0"
                     Height="45"
-                    IsEnabled="False"
                     ToolTip.Tip="{CompiledBinding BatchResize,
                                                   Mode=OneWay}"
                     Width="179">