浏览代码

Refactor gallery view models for ReactiveUI to R3 migration, W.I.P

Ruben 3 月之前
父节点
当前提交
d04e2566ac
共有 33 个文件被更改,包括 342 次插入516 次删除
  1. 6 2
      src/PicView.Avalonia/Crop/CropFunctions.cs
  2. 24 24
      src/PicView.Avalonia/CustomControls/GalleryAnimationControl.cs
  3. 60 31
      src/PicView.Avalonia/Gallery/GalleryFunctions.cs
  4. 7 6
      src/PicView.Avalonia/Gallery/GalleryLoad.cs
  5. 7 7
      src/PicView.Avalonia/Gallery/GalleryNavigation.cs
  6. 56 56
      src/PicView.Avalonia/Gallery/GalleryStretch.cs
  7. 9 7
      src/PicView.Avalonia/Navigation/ErrorHandling.cs
  8. 6 6
      src/PicView.Avalonia/Navigation/ImageIterator.cs
  9. 1 1
      src/PicView.Avalonia/Navigation/ImageLoader.cs
  10. 2 2
      src/PicView.Avalonia/Navigation/Slideshow.cs
  11. 5 8
      src/PicView.Avalonia/Navigation/UpdateImage.cs
  12. 21 16
      src/PicView.Avalonia/SettingsManagement/SettingsUpdater.cs
  13. 2 1
      src/PicView.Avalonia/StartUp/QuickLoad.cs
  14. 0 1
      src/PicView.Avalonia/StartUp/StartUpHelper.cs
  15. 12 11
      src/PicView.Avalonia/UI/HideInterfaceLogic.cs
  16. 8 1
      src/PicView.Avalonia/ViewModels/GalleryItemViewModel.cs
  17. 9 11
      src/PicView.Avalonia/ViewModels/GalleryViewModel.cs
  18. 1 251
      src/PicView.Avalonia/ViewModels/MainViewModel.cs
  19. 3 3
      src/PicView.Avalonia/Views/GallerySettingsView.axaml
  20. 13 13
      src/PicView.Avalonia/Views/GalleryView.axaml
  21. 6 6
      src/PicView.Avalonia/Views/MainView.axaml
  22. 3 3
      src/PicView.Avalonia/Views/UC/BottomGalleryItemSizeSlider.axaml
  23. 4 4
      src/PicView.Avalonia/Views/UC/BottomGalleryItemSizeSlider.axaml.cs
  24. 1 1
      src/PicView.Avalonia/Views/UC/Buttons/GalleryShortcut.axaml
  25. 3 3
      src/PicView.Avalonia/Views/UC/FullGalleryItemSizeSlider.axaml
  26. 3 3
      src/PicView.Avalonia/Views/UC/FullGalleryItemSizeSlider.axaml.cs
  27. 11 11
      src/PicView.Avalonia/Views/UC/GalleryItem.axaml
  28. 1 1
      src/PicView.Avalonia/Views/UC/GalleryItemSizeSlider.axaml
  29. 19 14
      src/PicView.Avalonia/Views/UC/GalleryItemSizeSlider.axaml.cs
  30. 13 8
      src/PicView.Avalonia/WindowBehavior/WindowResizing.cs
  31. 14 0
      src/PicView.Core/ViewModels/GlobalSettingsViewModel.cs
  32. 8 4
      src/PicView.Core/ViewModels/PicViewerModel.cs
  33. 4 0
      src/PicView.Core/ViewModels/SettingsViewModel.cs

+ 6 - 2
src/PicView.Avalonia/Crop/CropFunctions.cs

@@ -42,7 +42,7 @@ public static class CropFunctions
         // Hide bottom gallery when entering crop mode
         if (isBottomGalleryShown)
         {
-            vm.GalleryMode = GalleryMode.Closed;
+            vm.Gallery.GalleryMode.Value = GalleryMode.Closed;
             // Reset setting before resizing
             Settings.Gallery.IsBottomGalleryShown = false;
             await WindowResizing.SetSizeAsync(vm);
@@ -82,7 +82,11 @@ public static class CropFunctions
     {
         if (Settings.Gallery.IsBottomGalleryShown)
         {
-            vm.GalleryMode = GalleryMode.ClosedToBottom;
+            if (vm.Gallery is {} gallery)
+            {
+                gallery.GalleryMode.Value = GalleryMode.ClosedToBottom;
+            }
+            
             WindowResizing.SetSize(vm);
         }
 

+ 24 - 24
src/PicView.Avalonia/CustomControls/GalleryAnimationControl.cs

@@ -149,7 +149,7 @@ public class GalleryAnimationControl : UserControl
             IsVisible = true;
             Opacity = FullOpacity;
             Height = double.NaN;
-            ViewModel.GalleryOrientation = Orientation.Horizontal;
+            ViewModel.Gallery.GalleryOrientation.Value = Orientation.Horizontal;
         });
     }
 
@@ -173,13 +173,13 @@ public class GalleryAnimationControl : UserControl
                 Opacity = NoOpacity;
                 Height = parent.Bounds.Height;
                 UIHelper.GetGalleryView.BlurMask.BlurEnabled = true;
-                ViewModel.GalleryItemMargin = FullGalleryItemMargin;
+                ViewModel.Gallery.GalleryItem.ItemMargin.Value = FullGalleryItemMargin;
             });
 
             // Configure gallery
-            ViewModel.GalleryOrientation = Orientation.Vertical;
+            ViewModel.Gallery.GalleryOrientation.Value = Orientation.Vertical;
             GalleryStretchMode.DetermineStretchMode(ViewModel);
-            ViewModel.IsFullGalleryOpen = true;
+            ViewModel.Gallery.IsGalleryExpanded.Value = true;
 
             // Animate opacity
             var opacityAnimation = AnimationsHelper.OpacityAnimation(NoOpacity, FullOpacity, MediumAnimationSpeed);
@@ -189,7 +189,7 @@ public class GalleryAnimationControl : UserControl
             await Dispatcher.UIThread.InvokeAsync(() =>
             {
                 Opacity = FullOpacity;
-                ViewModel.GalleryVerticalAlignment = VerticalAlignment.Stretch;
+                ViewModel.Gallery.GalleryVerticalAlignment.Value = VerticalAlignment.Stretch;
                 GalleryNavigation.CenterScrollToSelectedItem(ViewModel);
             });
         }
@@ -219,7 +219,7 @@ public class GalleryAnimationControl : UserControl
 
             // Animate opacity
             var opacityAnimation = AnimationsHelper.OpacityAnimation(FullOpacity, NoOpacity, FastAnimationSpeed);
-            ViewModel.GalleryMargin = new Thickness(0);
+            ViewModel.Gallery.GalleryMargin.Value = new Thickness(0);
             await opacityAnimation.RunAsync(this);
 
             // Apply final state
@@ -258,17 +258,17 @@ public class GalleryAnimationControl : UserControl
                 Opacity = FullOpacity;
                 WindowResizing.SetSize(ViewModel);
                 UIHelper.GetGalleryView.BlurMask.BlurEnabled = false;
-                ViewModel.GalleryItemMargin = BottomGalleryItemMargin;
+                ViewModel.Gallery.GalleryItem.ItemMargin.Value = BottomGalleryItemMargin;
             });
 
             // Configure gallery
-            ViewModel.GalleryOrientation = Orientation.Horizontal;
+            ViewModel. Gallery.GalleryOrientation.Value = Orientation.Horizontal;
             GalleryStretchMode.DetermineStretchMode(ViewModel);
-            ViewModel.IsFullGalleryOpen = false;
-            ViewModel.GalleryVerticalAlignment = VerticalAlignment.Bottom;
+            ViewModel.Gallery.IsGalleryExpanded.Value = false;
+            ViewModel.Gallery.GalleryVerticalAlignment.Value = VerticalAlignment.Bottom;
 
             // Animate height
-            var to = ViewModel.GalleryHeight;
+            var to = GalleryFunctions.GetGalleryHeight(ViewModel);
             var heightAnimation = AnimationsHelper.HeightAnimation(ZeroHeight, to, FastAnimationSpeed);
             await heightAnimation.RunAsync(this);
 
@@ -298,7 +298,7 @@ public class GalleryAnimationControl : UserControl
             _isAnimating = true;
 
             // Animate closing
-            var from = ViewModel.GetBottomGalleryItemHeight + SizeDefaults.ScrollbarSize;
+            var from = ViewModel.Gallery.GalleryItem.BottomGalleryItemHeight.Value + SizeDefaults.ScrollbarSize;
             await Dispatcher.UIThread.InvokeAsync(() =>
             {
                 Height = from;
@@ -308,8 +308,8 @@ public class GalleryAnimationControl : UserControl
             });
 
             // Configure gallery
-            ViewModel.GalleryOrientation = Orientation.Horizontal;
-            ViewModel.IsFullGalleryOpen = false;
+            ViewModel.Gallery.GalleryOrientation.Value = Orientation.Horizontal;
+            ViewModel.Gallery.IsGalleryExpanded.Value = false;
 
             // Animate height
             var heightAnimation = AnimationsHelper.HeightAnimation(from, ZeroHeight, FastAnimationSpeed);
@@ -341,13 +341,13 @@ public class GalleryAnimationControl : UserControl
             _isAnimating = true;
 
             // Configure gallery
-            ViewModel.GalleryOrientation = Orientation.Vertical;
-            ViewModel.IsFullGalleryOpen = true;
+            ViewModel.Gallery.GalleryOrientation.Value = Orientation.Vertical;
+            ViewModel.Gallery.IsGalleryExpanded.Value = true;
             GalleryStretchMode.DetermineStretchMode(ViewModel);
-            ViewModel.GalleryItemMargin = FullGalleryItemMargin;
+            ViewModel.Gallery.GalleryItem.ItemMargin.Value = FullGalleryItemMargin;
 
             // Animate height
-            var from = ViewModel.GalleryHeight;
+            var from = GalleryFunctions.GetGalleryHeight(ViewModel);
             var to = parent.Bounds.Height;
             var heightAnimation = AnimationsHelper.HeightAnimation(from, to, MediumAnimationSpeed);
             await heightAnimation.RunAsync(this);
@@ -357,7 +357,7 @@ public class GalleryAnimationControl : UserControl
             {
                 Height = to;
                 UIHelper.GetGalleryView.BlurMask.BlurEnabled = true;
-                ViewModel.GalleryVerticalAlignment = VerticalAlignment.Stretch;
+                ViewModel.Gallery.GalleryVerticalAlignment.Value = VerticalAlignment.Stretch;
                 GalleryNavigation.CenterScrollToSelectedItem(ViewModel);
             });
         }
@@ -379,12 +379,12 @@ public class GalleryAnimationControl : UserControl
             _isAnimating = true;
 
             // Configure gallery
-            ViewModel.GalleryVerticalAlignment = VerticalAlignment.Bottom;
-            ViewModel.IsFullGalleryOpen = false;
+            ViewModel.Gallery.GalleryVerticalAlignment.Value = VerticalAlignment.Bottom;
+            ViewModel.Gallery.IsGalleryExpanded.Value = false;
 
             // Animate height
             var from = Bounds.Height;
-            var to = ViewModel.GalleryHeight;
+            var to = GalleryFunctions.GetGalleryHeight(ViewModel);
             var heightAnimation = AnimationsHelper.HeightAnimation(from, to, SlowAnimationSpeed);
             await heightAnimation.RunAsync(this);
 
@@ -398,8 +398,8 @@ public class GalleryAnimationControl : UserControl
             {
                 Height = parent.Bounds.Height;
                 UIHelper.GetGalleryView.BlurMask.BlurEnabled = false;
-                ViewModel.GalleryItemMargin = BottomGalleryItemMargin;
-                ViewModel.GalleryOrientation = Orientation.Horizontal;
+                ViewModel.Gallery.GalleryItem.ItemMargin.Value = BottomGalleryItemMargin;
+                ViewModel.Gallery.GalleryOrientation.Value = Orientation.Horizontal;
                 GalleryNavigation.CenterScrollToSelectedItem(ViewModel);
             });
         }

+ 60 - 31
src/PicView.Avalonia/Gallery/GalleryFunctions.cs

@@ -8,12 +8,41 @@ using PicView.Avalonia.ViewModels;
 using PicView.Avalonia.Views.UC;
 using PicView.Core.Gallery;
 using PicView.Core.Localization;
+using PicView.Core.Sizing;
 
 namespace PicView.Avalonia.Gallery;
 
 public static class GalleryFunctions
 {
-    public static bool RenameGalleryItem(int oldIndex, int newIndex, string newFileLocation, string newName, MainViewModel? vm)
+    public static double GetGalleryHeight(MainViewModel vm)
+    {
+        if (vm?.Gallery is not { } gallery)
+        {
+            return 0;
+        }
+
+        if (!Settings.Gallery.IsBottomGalleryShown || vm.IsSingleImage || Slideshow.IsRunning)
+        {
+            return 0;
+        }
+
+        if (Settings.WindowProperties.Fullscreen)
+        {
+            return Settings.Gallery.IsBottomGalleryShown
+                ? gallery.GalleryItem.BottomGalleryItemHeight.CurrentValue + (SizeDefaults.ScrollbarSize - 1)
+                : 0;
+        }
+
+        if (!Settings.Gallery.ShowBottomGalleryInHiddenUI && !vm.IsUIShown)
+        {
+            return 0;
+        }
+
+        return gallery.GalleryItem.BottomGalleryItemHeight.CurrentValue + (SizeDefaults.ScrollbarSize - 1);
+    }
+
+    public static bool RenameGalleryItem(int oldIndex, int newIndex, string newFileLocation, string newName,
+        MainViewModel? vm)
     {
         var mainView = UIHelper.GetMainView;
 
@@ -42,12 +71,8 @@ public static class GalleryFunctions
         {
             return Rename();
         }
-        Dispatcher.UIThread.InvokeAsync(Rename);
 
-        if (vm != null)
-        {
-            vm.SelectedGalleryItemIndex = NavigationManager.GetCurrentIndex;
-        }
+        Dispatcher.UIThread.InvokeAsync(Rename);
 
         return true;
 
@@ -57,6 +82,7 @@ public static class GalleryFunctions
             {
                 return false;
             }
+
             galleryItem.FileName.Text = newName;
             galleryItem.FileLocation.Text = newFileLocation;
             if (oldIndex == newIndex)
@@ -64,6 +90,7 @@ public static class GalleryFunctions
                 galleryListBox.Items[oldIndex] = galleryItem;
                 return true;
             }
+
             if (newIndex >= 0 && newIndex < galleryListBox.Items.Count)
             {
                 galleryListBox.Items.RemoveAt(oldIndex);
@@ -74,7 +101,7 @@ public static class GalleryFunctions
             return false;
         }
     }
-    
+
     public static bool RemoveGalleryItem(int index, MainViewModel? vm)
     {
         var mainView = UIHelper.GetMainView;
@@ -94,11 +121,6 @@ public static class GalleryFunctions
             Dispatcher.UIThread.InvokeAsync(Removal);
         }
 
-        if (vm != null)
-        {
-            vm.SelectedGalleryItemIndex = NavigationManager.GetCurrentIndex;
-        }
-
         return true;
 
         void Removal()
@@ -108,10 +130,12 @@ public static class GalleryFunctions
             {
                 return;
             }
+
             if (galleryListBox.Items[removalIndex] is not GalleryItem galleryItem)
             {
                 return;
             }
+
             galleryListBox.Items.Remove(galleryItem);
             if (galleryItem.GalleryImage.Source is IDisposable galleryImage)
             {
@@ -120,7 +144,8 @@ public static class GalleryFunctions
         }
     }
 
-    public static async Task<bool> AddGalleryItem(int index, FileInfo fileInfo, MainViewModel? vm, DispatcherPriority? priority = null)
+    public static async Task<bool> AddGalleryItem(int index, FileInfo fileInfo, MainViewModel? vm,
+        DispatcherPriority? priority = null)
     {
         var mainView = UIHelper.GetMainView;
 
@@ -131,7 +156,7 @@ public static class GalleryFunctions
         }
 
         GalleryItem? galleryItem;
-        var thumb = await GetThumbnails.GetThumbAsync(fileInfo, (uint)vm.GetGalleryItemHeight);
+        var thumb = await GetThumbnails.GetThumbAsync(fileInfo, (uint)vm.Gallery.GalleryItem.ItemHeight.Value);
         var galleryThumbInfo = GalleryThumbInfo.GalleryThumbHolder.GetThumbData(fileInfo);
         try
         {
@@ -173,7 +198,7 @@ public static class GalleryFunctions
                 {
                     galleryListBox.Items.Add(galleryItem);
                 }
-                
+
                 var isSvg = fileInfo.Extension.Equals(".svg", StringComparison.OrdinalIgnoreCase) ||
                             fileInfo.Extension.Equals(".svgz", StringComparison.OrdinalIgnoreCase);
                 if (isSvg)
@@ -262,7 +287,7 @@ public static class GalleryFunctions
         {
             Dispatcher.UIThread.Post(Center);
         }
-        
+
         return;
 
         void Center()
@@ -270,11 +295,12 @@ public static class GalleryFunctions
             var mainView = UIHelper.GetMainView;
 
             var galleryListBox = mainView.GalleryView.GalleryListBox;
-            if (vm.SelectedGalleryItemIndex < 0 || vm.SelectedGalleryItemIndex >= galleryListBox.Items.Count)
+            if (vm.PicViewer.Index.Value < 0 || vm.PicViewer.Index.Value >= galleryListBox.Items.Count)
             {
                 return;
             }
-            if (galleryListBox.Items[vm.SelectedGalleryItemIndex] is GalleryItem centerItem)
+
+            if (galleryListBox.Items[vm.PicViewer.Index.CurrentValue] is GalleryItem centerItem)
             {
                 galleryListBox.ScrollToCenterOfItem(centerItem);
             }
@@ -293,21 +319,22 @@ public static class GalleryFunctions
         }
 
         MenuManager.CloseMenus(vm);
+        vm.Gallery ??= new GalleryViewModel();
         if (Settings.Gallery.IsBottomGalleryShown)
         {
             if (IsFullGalleryOpen)
             {
                 // Switch to bottom gallery
                 IsFullGalleryOpen = false;
-                vm.GalleryMode = GalleryMode.FullToBottom;
-                vm.GetGalleryItemHeight = vm.GetBottomGalleryItemHeight;
+                vm.Gallery.GalleryMode.Value = GalleryMode.FullToBottom;
+                vm.Gallery.GalleryItem.ItemHeight.Value = vm.Gallery.GalleryItem.BottomGalleryItemHeight.CurrentValue;
             }
             else
             {
                 // Switch to full gallery
                 IsFullGalleryOpen = true;
-                vm.GalleryMode = GalleryMode.BottomToFull;
-                vm.GetGalleryItemHeight = vm.GetFullGalleryItemHeight;
+                vm.Gallery.GalleryMode.Value = GalleryMode.BottomToFull;
+                vm.Gallery.GalleryItem.ItemHeight.Value = vm.Gallery.GalleryItem.ExpandedGalleryItemHeight.CurrentValue;;
             }
         }
         else
@@ -316,18 +343,18 @@ public static class GalleryFunctions
             {
                 // close full gallery
                 IsFullGalleryOpen = false;
-                vm.GalleryMode = GalleryMode.FullToClosed;
+                vm.Gallery.GalleryMode.Value = GalleryMode.FullToClosed;
             }
             else
             {
                 // open full gallery
                 IsFullGalleryOpen = true;
-                vm.GalleryMode = GalleryMode.ClosedToFull;
-                vm.GetGalleryItemHeight = vm.GetFullGalleryItemHeight;
+                vm.Gallery.GalleryMode.Value = GalleryMode.ClosedToFull;
+                vm.Gallery.GalleryItem.ItemHeight.Value = vm.Gallery.GalleryItem.ExpandedGalleryItemHeight.CurrentValue;
             }
         }
 
-        
+
         _ = Task.Run(() => GalleryLoad.LoadGallery(vm, NavigationManager.GetInitialFileInfo?.DirectoryName));
     }
 
@@ -342,22 +369,23 @@ public static class GalleryFunctions
 
         if (Settings.Gallery.IsBottomGalleryShown)
         {
-            vm.GalleryMode = GalleryMode.BottomToClosed;
+            vm.Gallery.GalleryMode.Value = GalleryMode.BottomToClosed;
             vm.Translation.IsShowingBottomGallery.Value = TranslationManager.Translation.ShowBottomGallery;
             Settings.Gallery.IsBottomGalleryShown = false;
             IsFullGalleryOpen = false;
             return;
         }
 
+        vm.Gallery ??= new GalleryViewModel();
         IsFullGalleryOpen = false;
         Settings.Gallery.IsBottomGalleryShown = true;
         if (NavigationManager.CanNavigate(vm))
         {
-            vm.GalleryMode = GalleryMode.ClosedToBottom;
+            vm.Gallery.GalleryMode.Value = GalleryMode.ClosedToBottom;
         }
 
         vm.Translation.IsShowingBottomGallery.Value = TranslationManager.Translation.HideBottomGallery;
-        vm.IsBottomGalleryShown = true;
+        vm.Gallery.IsBottomGalleryShown.Value = true;
         if (!NavigationManager.CanNavigate(vm))
         {
             return;
@@ -368,8 +396,9 @@ public static class GalleryFunctions
 
     public static void OpenBottomGallery(MainViewModel vm)
     {
-        vm.GalleryMode = GalleryMode.ClosedToBottom;
-        vm.GalleryVerticalAlignment = VerticalAlignment.Bottom;
+        vm.Gallery ??= new GalleryViewModel();
+        vm.Gallery.GalleryMode.Value = GalleryMode.ClosedToBottom;
+        vm.Gallery.GalleryVerticalAlignment.Value = VerticalAlignment.Bottom;
     }
 
     public static void CloseGallery(MainViewModel vm)

+ 7 - 6
src/PicView.Avalonia/Gallery/GalleryLoad.cs

@@ -20,6 +20,8 @@ public static class GalleryLoad
         // TODO: When list larger than 500, lazy load this when scrolling instead.
         // Figure out how to support virtualization. 
 
+        vm.Gallery ??= new GalleryViewModel();
+
         if (IsLoading || !NavigationManager.CanNavigate(vm) || string.IsNullOrEmpty(currentDirectory))
         {
             return;
@@ -61,14 +63,14 @@ public static class GalleryLoad
         // Make sure height is set
         if (Settings.Gallery.IsBottomGalleryShown && !GalleryFunctions.IsFullGalleryOpen)
         {
-            vm.GetGalleryItemHeight = vm.GetBottomGalleryItemHeight;
+            vm.Gallery.GalleryItem.ItemHeight.Value = vm.Gallery.GalleryItem.BottomGalleryItemHeight.CurrentValue;
         }
 
         _cancellationTokenSource = new CancellationTokenSource();
         _currentDirectory = currentDirectory;
         IsLoading = true;
         var index = NavigationManager.GetCurrentIndex;
-        var galleryItemSize = Math.Max(vm.GetBottomGalleryItemHeight, vm.GetFullGalleryItemHeight);
+        var galleryItemSize = Math.Max(vm.Gallery.GalleryItem.BottomGalleryItemHeight.CurrentValue, vm.Gallery.GalleryItem.ExpandedGalleryItemHeight.CurrentValue);
 
         var endIndex = NavigationManager.GetCount;
         // Set priority low when loading excess images to ensure app responsiveness
@@ -119,8 +121,7 @@ public static class GalleryLoad
                     {
                         return;
                     }
-
-                    vm.SelectedGalleryItemIndex = i;
+                    
                     galleryListBox.SelectedItem = galleryItem;
                 }, priority, _cancellationTokenSource.Token);
             }
@@ -295,10 +296,10 @@ public static class GalleryLoad
             // Check if the bottom gallery should be shown
             if (!GalleryFunctions.IsFullGalleryOpen)
             {
-                if (vm.GalleryMode is GalleryMode.BottomToClosed or GalleryMode.FullToClosed or GalleryMode.Closed)
+                if (vm.Gallery.GalleryMode.CurrentValue is GalleryMode.BottomToClosed or GalleryMode.FullToClosed or GalleryMode.Closed)
                 {
                     // Trigger animation to show it
-                    vm.GalleryMode = GalleryMode.ClosedToBottom;
+                    vm.Gallery.GalleryMode.Value = GalleryMode.ClosedToBottom;
                 }
             }
 

+ 7 - 7
src/PicView.Avalonia/Gallery/GalleryNavigation.cs

@@ -63,14 +63,14 @@ public static class GalleryNavigation
         {
             var listbox = UIHelper.GetGalleryView.GalleryListBox;
 
-            if (listbox is null || vm.SelectedGalleryItemIndex < 0 || vm.SelectedGalleryItemIndex >= listbox.Items.Count)
+            if (listbox is null || vm.PicViewer.Index.CurrentValue < 0 || vm.PicViewer.Index.CurrentValue >= listbox.Items.Count)
             {
                 return;
             }
 
             try
             {
-                listbox.ScrollToCenterOfItem(listbox.Items[vm.SelectedGalleryItemIndex] as GalleryItem);
+                listbox.ScrollToCenterOfItem(listbox.Items[vm.PicViewer.Index.CurrentValue] as GalleryItem);
             }
             catch (Exception e)
             {
@@ -83,7 +83,7 @@ public static class GalleryNavigation
     
     public static void NavigateGallery(Direction direction, MainViewModel vm)
     {
-        var highlightedGalleryItem = vm.SelectedGalleryItemIndex;
+        var highlightedGalleryItem = vm.PicViewer.Index.CurrentValue;
         var galleryItems = GetGalleryItems();
 
         if (highlightedGalleryItem < 0 || highlightedGalleryItem >= galleryItems.Count)
@@ -110,7 +110,7 @@ public static class GalleryNavigation
     
     public static void NavigateGallery(bool last, MainViewModel vm)
     {
-        var highlightedGalleryItem = vm.SelectedGalleryItemIndex;
+        var highlightedGalleryItem = vm.PicViewer.Index.CurrentValue;
         var galleryItems = GetGalleryItems();
         
         if (highlightedGalleryItem < 0 || highlightedGalleryItem >= galleryItems.Count)
@@ -159,7 +159,7 @@ public static class GalleryNavigation
 
     public static void SetHighlightedGalleryItem(MainViewModel vm, int index)
     {
-        vm.SelectedGalleryItemIndex = index;
+        vm.PicViewer.Index.Value = index;
         CenterScrollToSelectedItem(vm); // Ensure the selected item is in view
     }
 
@@ -176,9 +176,9 @@ public static class GalleryNavigation
             return;
         }
         GalleryFunctions.ToggleGallery(vm);
-        if (vm.SelectedGalleryItemIndex != NavigationManager.GetCurrentIndex) 
+        if (vm.PicViewer.Index.CurrentValue != NavigationManager.GetCurrentIndex) 
         {
-            await NavigationManager.Navigate(vm.SelectedGalleryItemIndex, vm).ConfigureAwait(false);
+            await NavigationManager.Navigate(vm.PicViewer.Index.CurrentValue, vm).ConfigureAwait(false);
         }
     }
     

+ 56 - 56
src/PicView.Avalonia/Gallery/GalleryStretch.cs

@@ -7,45 +7,45 @@ public static class GalleryStretchMode
     public static void DetermineStretchMode(MainViewModel vm)
     {
         // Reset all boolean properties
-        vm.IsUniformMenuChecked = false;
-        vm.IsUniformBottomChecked = false;
-        vm.IsUniformFullChecked = false;
+        vm.Gallery.IsUniformMenuChecked.Value = false;
+        vm.Gallery.IsUniformBottomChecked.Value = false;
+        vm.Gallery.IsUniformFullChecked.Value = false;
         
-        vm.IsUniformToFillMenuChecked = false;
-        vm.IsUniformToFillBottomChecked = false;
-        vm.IsUniformToFillFullChecked = false;
+        vm.Gallery.IsUniformToFillMenuChecked.Value = false;
+        vm.Gallery.IsUniformToFillBottomChecked.Value = false;
+        vm.Gallery.IsUniformToFillFullChecked.Value = false;
         
-        vm.IsFillMenuChecked = false;
-        vm.IsFillBottomChecked = false;
-        vm.IsFillFullChecked = false;
+        vm.Gallery.IsFillMenuChecked.Value = false;
+        vm.Gallery.IsFillBottomChecked.Value = false;
+        vm.Gallery.IsFillFullChecked.Value = false;
         
-        vm.IsNoneMenuChecked = false;
-        vm.IsNoneBottomChecked = false;
-        vm.IsNoneFullChecked = false;
+        vm.Gallery.IsNoneMenuChecked.Value = false;
+        vm.Gallery.IsNoneBottomChecked.Value = false;
+        vm.Gallery.IsNoneFullChecked.Value = false;
         
-        vm.IsSquareMenuChecked = false;
-        vm.IsSquareBottomChecked = false;
-        vm.IsSquareFullChecked = false;
+        vm.Gallery.IsSquareMenuChecked.Value = false;
+        vm.Gallery.IsSquareBottomChecked.Value = false;
+        vm.Gallery.IsSquareFullChecked.Value = false;
         
-        vm.IsFillSquareMenuChecked = false;
-        vm.IsFillSquareBottomChecked = false;
-        vm.IsFillSquareFullChecked = false;
+        vm.Gallery.IsFillSquareMenuChecked.Value = false;
+        vm.Gallery.IsFillSquareBottomChecked.Value = false;
+        vm.Gallery.IsFillSquareFullChecked.Value = false;
 
         if (Settings.Gallery.FullGalleryStretchMode.Equals("Square", StringComparison.OrdinalIgnoreCase))
         {
-            vm.IsSquareFullChecked = true;
+            vm.Gallery.IsSquareFullChecked.Value = true;
             if (GalleryFunctions.IsFullGalleryOpen)
             {
-                vm.IsSquareMenuChecked = true;
+                vm.Gallery.IsSquareMenuChecked.Value = true;
                 SetSquareStretch(vm);
             }
         }
         else if (Settings.Gallery.FullGalleryStretchMode.Equals("FillSquare", StringComparison.OrdinalIgnoreCase))
         {
-            vm.IsFillSquareFullChecked = true;
+            vm.Gallery.IsFillSquareFullChecked.Value = true;
             if (GalleryFunctions.IsFullGalleryOpen)
             {
-                vm.IsFillSquareMenuChecked = true;
+                vm.Gallery.IsFillSquareMenuChecked.Value = true;
                 SetSquareFillStretch(vm);
             }
         }
@@ -59,31 +59,31 @@ public static class GalleryStretchMode
         }
         else
         {
-            vm.GetGalleryItemWidth = double.NaN;
+            vm.Gallery.GalleryItem.ItemWidth.Value = double.NaN;
             if (GalleryFunctions.IsFullGalleryOpen)
             {
-                vm.IsUniformMenuChecked = true;
+                vm.Gallery.IsUniformMenuChecked.Value = true;
                 SetGalleryStretch(vm, Stretch.Uniform);
             }
-            vm.IsUniformFullChecked = true;
+            vm.Gallery.IsUniformFullChecked.Value = true;
         }
         
 
         if (Settings.Gallery.BottomGalleryStretchMode.Equals("Square", StringComparison.OrdinalIgnoreCase))
         {
-            vm.IsSquareBottomChecked = true;
+            vm.Gallery.IsSquareBottomChecked.Value = true;
             if (!GalleryFunctions.IsFullGalleryOpen)
             {
-                vm.IsSquareMenuChecked = true;
+                vm.Gallery.IsSquareMenuChecked.Value = true;
                 SetSquareStretch(vm);
             }
         }
         else if (Settings.Gallery.BottomGalleryStretchMode.Equals("FillSquare", StringComparison.OrdinalIgnoreCase))
         {
-            vm.IsFillSquareBottomChecked = true;
+            vm.Gallery.IsFillSquareBottomChecked.Value = true;
             if (!GalleryFunctions.IsFullGalleryOpen)
             {
-                vm.IsFillSquareMenuChecked = true;
+                vm.Gallery.IsFillSquareMenuChecked.Value = true;
                 SetSquareFillStretch(vm);
             }
         }
@@ -97,10 +97,10 @@ public static class GalleryStretchMode
         }
         else
         {
-            vm.IsUniformBottomChecked = true;
+            vm.Gallery.IsUniformBottomChecked.Value = true;
             if (!GalleryFunctions.IsFullGalleryOpen)
             {
-                vm.IsUniformMenuChecked = true;
+                vm.Gallery.IsUniformMenuChecked.Value = true;
                 SetGalleryStretch(vm, Stretch.Uniform);
             }
         }
@@ -115,82 +115,82 @@ public static class GalleryStretchMode
                 case Stretch.Uniform:
                     if (GalleryFunctions.IsFullGalleryOpen)
                     {
-                        vm.IsUniformFullChecked = true;
+                        vm.Gallery.IsUniformFullChecked.Value = true;
                         if (isFullGallery)
                         {
-                            vm.IsUniformMenuChecked = true;
+                            vm.Gallery.IsUniformMenuChecked.Value = true;
                         }
                     }
                     else
                     {
-                        vm.IsUniformBottomChecked = true;
+                        vm.Gallery.IsUniformBottomChecked.Value = true;
                         if (!isFullGallery)
                         {
-                            vm.IsUniformMenuChecked = true;
+                            vm.Gallery.IsUniformMenuChecked.Value = true;
                         }
                     }
                     break;
                 case Stretch.UniformToFill:
                     if (GalleryFunctions.IsFullGalleryOpen)
                     {
-                        vm.IsUniformToFillFullChecked = true;
+                        vm.Gallery.IsUniformToFillFullChecked.Value = true;
                         if (isFullGallery)
                         {
-                            vm.IsUniformToFillMenuChecked = true;
+                            vm.Gallery.IsUniformToFillMenuChecked.Value = true;
                         }
                     }
                     else
                     {
-                        vm.IsUniformToFillBottomChecked = true;
+                        vm.Gallery.IsUniformToFillBottomChecked.Value = true;
                         if (!isFullGallery)
                         {
-                            vm.IsUniformToFillMenuChecked = true;
+                            vm.Gallery.IsUniformToFillMenuChecked.Value = true;
                         }
                     }
                     break;
                 case Stretch.Fill:
                     if (GalleryFunctions.IsFullGalleryOpen)
                     {
-                        vm.IsFillFullChecked = true;
+                        vm.Gallery.IsFillFullChecked.Value = true;
                         if (isFullGallery)
                         {
-                            vm.IsFillMenuChecked = true;
+                            vm.Gallery.IsFillMenuChecked.Value = true;
                         }
                     }
                     else
                     {
-                        vm.IsFillBottomChecked = true;
+                        vm.Gallery.IsFillBottomChecked.Value = true;
                         if (!isFullGallery)
                         {
-                            vm.IsFillMenuChecked = true;
+                            vm.Gallery.IsFillMenuChecked.Value = true;
                         }
                     }
                     break;
                 case Stretch.None:
                     if (GalleryFunctions.IsFullGalleryOpen)
                     {
-                        vm.IsNoneFullChecked = true;
+                        vm.Gallery.IsNoneFullChecked.Value = true;
                         if (isFullGallery)
                         {
-                            vm.IsNoneMenuChecked = true;
+                            vm.Gallery.IsNoneMenuChecked.Value = true;
                         }
                     }
                     else
                     {
-                        vm.IsNoneBottomChecked = true;
+                        vm.Gallery.IsNoneBottomChecked.Value = true;
                         if (!isFullGallery)
                         {
-                            vm.IsNoneMenuChecked = true;
+                            vm.Gallery.IsNoneMenuChecked.Value = true;
                         }
                     }
                     break;
                 default:
                     if (!GalleryFunctions.IsFullGalleryOpen)
                     {
-                        vm.IsUniformMenuChecked = true;
+                        vm.Gallery.IsUniformMenuChecked.Value = true;
                     }
-                    vm.IsUniformFullChecked = true;
-                    vm.IsUniformBottomChecked = true;
+                    vm.Gallery.IsUniformFullChecked.Value = true;
+                    vm.Gallery.IsUniformBottomChecked.Value = true;
                     break;
             }
         }
@@ -198,20 +198,20 @@ public static class GalleryStretchMode
     
     public static void SetGalleryStretch(MainViewModel vm, Stretch stretch)
     {
-        vm.GetGalleryItemWidth = double.NaN;
-        vm.GalleryStretch = stretch;
+        vm.Gallery.GalleryItem.ItemWidth.Value = double.NaN;
+        vm.Gallery.GalleryStretch.Value = stretch;
     }
 
     public static void SetSquareStretch(MainViewModel vm)
     {
-        vm.GetGalleryItemWidth = vm.GetGalleryItemHeight;
-        vm.GalleryStretch = Stretch.Uniform;
+        vm.Gallery.GalleryItem.ItemWidth.Value  = vm.Gallery.GalleryItem.ItemHeight.Value;
+        vm.Gallery.GalleryStretch.Value = Stretch.Uniform;
     }
     
     public static void SetSquareFillStretch(MainViewModel vm)
     {
-        vm.GetGalleryItemWidth = vm.GetGalleryItemHeight;
-        vm.GalleryStretch = Stretch.Fill;
+        vm.Gallery.GalleryItem.ItemWidth.Value  = vm.Gallery.GalleryItem.ItemHeight.Value;;
+        vm.Gallery.GalleryStretch.Value = Stretch.Fill;
     }
 
     public static void ChangeBottomGalleryItemStretch(MainViewModel vm, Stretch stretch)

+ 9 - 7
src/PicView.Avalonia/Navigation/ErrorHandling.cs

@@ -41,20 +41,16 @@ public static class ErrorHandling
                 {
                     startUpMenu.Width = SizeDefaults.WindowMinSize;
                     startUpMenu.Height = SizeDefaults.WindowMinSize;
-                    if (Settings.Gallery.IsBottomGalleryShown)
-                    {
-                        vm.GalleryWidth = SizeDefaults.WindowMinSize;
-                    }
+                    vm.PicViewer.GalleryWidth.Value = SizeDefaults.WindowMinSize;
                 }
+
                 vm.CurrentView = startUpMenu;
             }
             
             TitleManager.SetNoImageTitle(vm);
-
-            vm.GalleryMode = GalleryMode.Closed;
             GalleryFunctions.Clear();
             MenuManager.CloseMenus(vm);
-            vm.GalleryMargin = new Thickness(0, 0, 0, 0);
+
             vm.GetIndex = 0;
             vm.PlatformService.StopTaskbarProgress();
             vm.IsLoading = false;
@@ -64,6 +60,12 @@ public static class ErrorHandling
             {
                 UIHelper.GetEditableTitlebar.TextBlock.TextAlignment = TextAlignment.Center;
             }
+            if (vm.Gallery is null)
+            {
+                return;
+            }
+            vm.Gallery.GalleryMode.Value = GalleryMode.Closed;
+            vm.Gallery.GalleryMargin.Value = new Thickness(0, 0, 0, 0);
         }
     }
 

+ 6 - 6
src/PicView.Avalonia/Navigation/ImageIterator.cs

@@ -232,9 +232,9 @@ public class ImageIterator : IAsyncDisposable
             {
                 if (Settings.Gallery.IsBottomGalleryShown && ImagePaths.Count > 1)
                 {
-                    if (_vm.GalleryMode is GalleryMode.BottomToClosed or GalleryMode.FullToClosed)
+                    if (_vm.Gallery.GalleryMode.CurrentValue is GalleryMode.BottomToClosed or GalleryMode.FullToClosed)
                     {
-                        _vm.GalleryMode = GalleryMode.ClosedToBottom;
+                        _vm.Gallery.GalleryMode.Value = GalleryMode.ClosedToBottom;
                     }
                 }
 
@@ -299,12 +299,12 @@ public class ImageIterator : IAsyncDisposable
                 {
                     if (ImagePaths.Count == 1)
                     {
-                        _vm.GalleryMode = GalleryMode.BottomToClosed;
+                        _vm.Gallery.GalleryMode.Value = GalleryMode.BottomToClosed;
                     }
                 }
 
                 var indexOf = ImagePaths.FindIndex(x => x.FullName.Equals(_vm.PicViewer.FileInfo.CurrentValue.FullName));
-                _vm.SelectedGalleryItemIndex = indexOf; // Fixes deselection bug 
+                _vm.PicViewer.Index.Value = indexOf; // Fixes deselection bug 
                 CurrentIndex = indexOf;
                 if (isSameFile)
                 {
@@ -389,7 +389,7 @@ public class ImageIterator : IAsyncDisposable
                     _vm));
             if (sameFile)
             {
-                _vm.SelectedGalleryItemIndex = newIndex;
+                _vm.PicViewer.Index.Value = newIndex;
                 GalleryFunctions.CenterGallery(_vm);
             }
         }
@@ -798,7 +798,7 @@ public class ImageIterator : IAsyncDisposable
         {
             TitleManager.SetLoadingTitle(_vm);
 
-            _vm.SelectedGalleryItemIndex = index;
+            _vm.PicViewer.Index.Value = index;
             if (Settings.Gallery.IsBottomGalleryShown)
             {
                 GalleryNavigation.CenterScrollToSelectedItem(_vm);

+ 1 - 1
src/PicView.Avalonia/Navigation/ImageLoader.cs

@@ -121,7 +121,7 @@ public static class ImageLoader
                     await NavigationManager.CheckIfTiffAndUpdate(vm, fileInfo, index);
                     if (Settings.Gallery.IsBottomGalleryShown && NavigationManager.GetCount > 0)
                     {
-                        vm.GalleryMode = GalleryMode.ClosedToBottom;
+                        vm.Gallery.GalleryMode.Value = GalleryMode.ClosedToBottom;
                     }
                 }
                 else

+ 2 - 2
src/PicView.Avalonia/Navigation/Slideshow.cs

@@ -58,7 +58,7 @@ public static class Slideshow
 
         if (Settings.Gallery.IsBottomGalleryShown)
         {
-            vm.GalleryMode = GalleryMode.ClosedToBottom;
+            vm.Gallery.GalleryMode.Value = GalleryMode.ClosedToBottom;
         }
         
         _timer.Stop();
@@ -118,7 +118,7 @@ public static class Slideshow
 
         if (GalleryFunctions.IsFullGalleryOpen || Settings.Gallery.IsBottomGalleryShown)
         {
-            vm.GalleryMode = GalleryMode.BottomToClosed;
+            vm.Gallery.GalleryMode.Value = GalleryMode.BottomToClosed;
         }
     }
 }

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

@@ -153,13 +153,10 @@ public static class UpdateImage
             await Dispatcher.UIThread.InvokeAsync(() => { WindowFunctions.CenterWindowOnScreen(); });
         }
 
-        if (vm.SelectedGalleryItemIndex != index)
+        vm.PicViewer.Index.Value = index;
+        if (Settings.Gallery.IsBottomGalleryShown)
         {
-            vm.SelectedGalleryItemIndex = index;
-            if (Settings.Gallery.IsBottomGalleryShown)
-            {
-                GalleryNavigation.CenterScrollToSelectedItem(vm);
-            }
+            GalleryNavigation.CenterScrollToSelectedItem(vm);
         }
         
         SetStats(vm, preLoadValue.ImageModel);
@@ -287,8 +284,8 @@ public static class UpdateImage
 
         if (Settings.Gallery.IsBottomGalleryShown)
         {
-            vm.GalleryMode = GalleryMode.Closed;
-            vm.GalleryMargin = new Thickness(0);
+            vm.Gallery.GalleryMode.Value = GalleryMode.Closed;
+            vm.Gallery.GalleryMargin.Value = new Thickness(0);
         }
 
         vm.IsSingleImage = true;

+ 21 - 16
src/PicView.Avalonia/SettingsManagement/SettingsUpdater.cs

@@ -18,25 +18,29 @@ public static class SettingsUpdater
 {
     public static void ValidateGallerySettings(MainViewModel vm, bool settingsExists)
     {
-        vm.GetFullGalleryItemHeight = Settings.Gallery.ExpandedGalleryItemSize;
-        vm.GetBottomGalleryItemHeight = Settings.Gallery.BottomGalleryItemSize;
+        if (vm.Gallery is not {} gallery)
+        {
+            return;
+        }
+        vm.Gallery.GalleryItem.ExpandedGalleryItemHeight.Value  = Settings.Gallery.ExpandedGalleryItemSize;
+        vm.Gallery.GalleryItem.BottomGalleryItemHeight.Value = Settings.Gallery.BottomGalleryItemSize;
         if (!settingsExists)
         {
-            vm.GetBottomGalleryItemHeight = GalleryDefaults.DefaultBottomGalleryHeight;
-            vm.GetFullGalleryItemHeight = GalleryDefaults.DefaultFullGalleryHeight;
+            vm.Gallery.GalleryItem.BottomGalleryItemHeight.Value = GalleryDefaults.DefaultBottomGalleryHeight;
+            vm.Gallery.GalleryItem.ExpandedGalleryItemHeight.Value = GalleryDefaults.DefaultFullGalleryHeight;
         }
 
         // Set default gallery sizes if they are out of range or upgrading from an old version
-        if (vm.GetBottomGalleryItemHeight < vm.MinBottomGalleryItemHeight ||
-            vm.GetBottomGalleryItemHeight > vm.MaxBottomGalleryItemHeight)
+        if (vm.Gallery.GalleryItem.BottomGalleryItemHeight.CurrentValue < GalleryDefaults.MinBottomGalleryItemHeight ||
+            vm.Gallery.GalleryItem.BottomGalleryItemHeight.CurrentValue > GalleryDefaults.MaxBottomGalleryItemHeight)
         {
-            vm.GetBottomGalleryItemHeight = GalleryDefaults.DefaultBottomGalleryHeight;
+            vm.Gallery.GalleryItem.BottomGalleryItemHeight.Value = GalleryDefaults.DefaultBottomGalleryHeight;
         }
 
-        if (vm.GetFullGalleryItemHeight < vm.MinFullGalleryItemHeight ||
-            vm.GetFullGalleryItemHeight > vm.MaxFullGalleryItemHeight)
+        if (vm.Gallery.GalleryItem.ExpandedGalleryItemHeight.CurrentValue < GalleryDefaults.MinFullGalleryItemHeight ||
+            vm.Gallery.GalleryItem.ExpandedGalleryItemHeight.CurrentValue > GalleryDefaults.MaxFullGalleryItemHeight)
         {
-            vm.GetFullGalleryItemHeight = GalleryDefaults.DefaultFullGalleryHeight;
+            vm.Gallery.GalleryItem.ExpandedGalleryItemHeight.Value = GalleryDefaults.DefaultFullGalleryHeight;
         }
 
         if (settingsExists)
@@ -75,8 +79,6 @@ public static class SettingsUpdater
         vm.GetSlideshowSpeed = Settings.UIProperties.SlideShowTimer;
         vm.GetZoomSpeed = Settings.Zoom.ZoomSpeed;
         vm.PicViewer.IsShowingSideBySide.Value = Settings.ImageScaling.ShowImageSideBySide;
-        vm.IsBottomGalleryShown = Settings.Gallery.IsBottomGalleryShown;
-        vm.IsBottomGalleryShownInHiddenUI = Settings.Gallery.ShowBottomGalleryInHiddenUI;
         vm.IsAvoidingZoomingOut  = Settings.Zoom.AvoidZoomingOut;
         vm.IsUIShown  = Settings.UIProperties.ShowInterface;
         vm.IsTopToolbarShown  = Settings.UIProperties.ShowInterface;
@@ -116,10 +118,13 @@ public static class SettingsUpdater
             {
                 TurnOffUsingTouchpad(vm);
             }
-        
-            vm.GetBottomGalleryItemHeight = GalleryDefaults.DefaultBottomGalleryHeight;
-            vm.GetFullGalleryItemHeight = GalleryDefaults.DefaultFullGalleryHeight;
-        
+
+            if (vm.Gallery is not null)
+            {
+                vm.Gallery.GalleryItem.BottomGalleryItemHeight.Value = GalleryDefaults.DefaultBottomGalleryHeight;
+                vm.Gallery.GalleryItem.ExpandedGalleryItemHeight.Value = GalleryDefaults.DefaultFullGalleryHeight;
+            }
+            
             if (string.IsNullOrWhiteSpace(Settings.Gallery.BottomGalleryStretchMode))
             {
                 Settings.Gallery.BottomGalleryStretchMode = "UniformToFill";

+ 2 - 1
src/PicView.Avalonia/StartUp/QuickLoad.cs

@@ -277,6 +277,7 @@ public static class QuickLoad
 
         if (Settings.Gallery.IsBottomGalleryShown)
         {
+            vm.Gallery = new GalleryViewModel();
             bool loadGallery;
             if (!vm.IsUIShown)
             {
@@ -289,7 +290,7 @@ public static class QuickLoad
 
             if (loadGallery)
             {
-                vm.GalleryMode = GalleryMode.BottomNoAnimation;
+                vm.Gallery.GalleryMode.Value = GalleryMode.BottomNoAnimation;
                 tasks.Add(GalleryLoad.LoadGallery(vm, fileInfo.DirectoryName));
             }
         }

+ 0 - 1
src/PicView.Avalonia/StartUp/StartUpHelper.cs

@@ -127,7 +127,6 @@ public static class StartUpHelper
         HandleThemeUpdates(vm);
         
         UIHelper.SetControls(desktop);
-
         SettingsUpdater.ValidateGallerySettings(vm, settingsExists);
         
         // Need to delay setting fullscreen or maximized until after the window is shown to select the correct monitor

+ 12 - 11
src/PicView.Avalonia/UI/HideInterfaceLogic.cs

@@ -27,21 +27,22 @@ public static class HideInterfaceLogic
             vm.Translation.IsShowingUI.Value = TranslationManager.Translation.ShowUI;
             if (!GalleryFunctions.IsFullGalleryOpen)
             {
+                vm.Gallery ??= new GalleryViewModel();
                 if (!Settings.Gallery.ShowBottomGalleryInHiddenUI)
                 {
-                    vm.GalleryMode = GalleryMode.Closed;
+                    vm.Gallery.GalleryMode.Value = GalleryMode.Closed;
                     await Dispatcher.UIThread.InvokeAsync(() =>
                     {
                         if (UIHelper.GetGalleryView.Bounds.Height > 0)
                         {
-                            vm.GalleryMode = GalleryMode.BottomToClosed;
+                            vm.Gallery.GalleryMode.Value = GalleryMode.BottomToClosed;
                         }
                     });
-                    vm.IsBottomGalleryShown = false;
+                    vm.Gallery.IsBottomGalleryShown.Value = false;
                 }
                 else
                 {
-                    vm.IsBottomGalleryShown = Settings.Gallery.ShowBottomGalleryInHiddenUI;
+                    vm.Gallery.IsBottomGalleryShown.Value = Settings.Gallery.ShowBottomGalleryInHiddenUI;
                 }
             }
         }
@@ -67,18 +68,18 @@ public static class HideInterfaceLogic
                         {
                             if (UIHelper.GetGalleryView.Bounds.Height <= 0)
                             {
-                                vm.GalleryMode = GalleryMode.Closed;
+                                vm.Gallery.GalleryMode.Value = GalleryMode.Closed;
                                 GalleryFunctions.OpenBottomGallery(vm);
                             }
                         });
                         _ = GalleryLoad.LoadGallery(vm, vm.PicViewer.FileInfo.CurrentValue.DirectoryName);
                     }
 
-                    vm.IsBottomGalleryShown = true;
+                    vm.Gallery.IsBottomGalleryShown.Value = true;
                 }
                 else
                 {
-                    vm.IsBottomGalleryShown = false;
+                    vm.Gallery.IsBottomGalleryShown.Value = false;
                 }
             }
         }
@@ -122,18 +123,18 @@ public static class HideInterfaceLogic
     {
         Settings.Gallery.ShowBottomGalleryInHiddenUI = !Settings.Gallery
             .ShowBottomGalleryInHiddenUI;
-        vm.IsBottomGalleryShownInHiddenUI = Settings.Gallery.ShowBottomGalleryInHiddenUI;
+        vm.GLobalSettings.ShowBottomGalleryInHiddenUI.Value = Settings.Gallery.ShowBottomGalleryInHiddenUI;
 
-        if (!GalleryFunctions.IsFullGalleryOpen)
+        if (!GalleryFunctions.IsFullGalleryOpen && vm.Gallery is not null)
         {
             if (!Settings.UIProperties.ShowInterface && !Settings.Gallery
                     .ShowBottomGalleryInHiddenUI)
             {
-                vm.IsBottomGalleryShown = false;
+                vm.Gallery.IsBottomGalleryShown.Value = false;
             }
             else
             {
-                vm.IsBottomGalleryShown = Settings.Gallery.IsBottomGalleryShown;
+                vm.Gallery.IsBottomGalleryShown.Value = Settings.Gallery.IsBottomGalleryShown;
             }
         }
         

+ 8 - 1
src/PicView.Avalonia/ViewModels/GalleryItemViewModel.cs

@@ -11,7 +11,10 @@ public class GalleryItemViewModel : IDisposable
         Disposable.Dispose(ItemWidth,
             ItemHeight,
             ItemMargin,
-            ExpandedGalleryItemWidth);
+            ExpandedGalleryItemWidth,
+            ExpandedGalleryItemHeight,
+            BottomGalleryItemWidth,
+            BottomGalleryItemHeight);
     }
 
     public BindableReactiveProperty<double> ItemWidth { get; } = new(0);
@@ -20,6 +23,10 @@ public class GalleryItemViewModel : IDisposable
     public BindableReactiveProperty<Thickness> ItemMargin { get; } = new();
 
     public BindableReactiveProperty<double> ExpandedGalleryItemWidth { get; } = new(0);
+    public BindableReactiveProperty<double> ExpandedGalleryItemHeight { get; } = new(0);
+    
+    public BindableReactiveProperty<double> BottomGalleryItemWidth { get; } = new(0);
+    public BindableReactiveProperty<double> BottomGalleryItemHeight { get; } = new(0);
 
     public double MaxExpandedGalleryItemHeight => GalleryDefaults.MaxFullGalleryItemHeight;
     public double MinExpandedGalleryItemHeight => GalleryDefaults.MinFullGalleryItemHeight;

+ 9 - 11
src/PicView.Avalonia/ViewModels/GalleryViewModel.cs

@@ -1,8 +1,9 @@
 using Avalonia;
+using Avalonia.Layout;
+using Avalonia.Media;
 using PicView.Avalonia.Functions;
 using PicView.Avalonia.Gallery;
 using PicView.Core.Gallery;
-using PicView.Core.Models;
 using R3;
 
 namespace PicView.Avalonia.ViewModels;
@@ -13,8 +14,6 @@ public class GalleryViewModel : IDisposable
 
     public BindableReactiveProperty<Thickness> GalleryMargin { get; } = new();
 
-    public BindableReactiveProperty<double> GalleryWidth { get; } = new(0);
-
     public BindableReactiveProperty<bool> IsBottomGalleryShown { get; } = new(Settings.Gallery.IsBottomGalleryShown);
 
     public BindableReactiveProperty<bool> IsBottomGalleryShownInHiddenUI { get; } =
@@ -22,9 +21,9 @@ public class GalleryViewModel : IDisposable
 
     public BindableReactiveProperty<GalleryMode> GalleryMode { get; } = new(Core.Gallery.GalleryMode.Closed);
 
-    public BindableReactiveProperty<CommonModels.Stretch> GalleryStretch { get; } = new();
-    public BindableReactiveProperty<CommonModels.VerticalAlignment> GalleryVerticalAlignment { get; } = new();
-    public BindableReactiveProperty<CommonModels.Orientation> GalleryOrientation { get; } = new();
+    public BindableReactiveProperty<Stretch> GalleryStretch { get; } = new();
+    public BindableReactiveProperty<VerticalAlignment> GalleryVerticalAlignment { get; } = new();
+    public BindableReactiveProperty<Orientation> GalleryOrientation { get; } = new();
 
     public BindableReactiveProperty<bool> IsGalleryExpanded { get; } = new();
     
@@ -69,10 +68,10 @@ public class GalleryViewModel : IDisposable
     #endregion
 
     #region Commands
-    public required ReactiveCommand ToggleGalleryCommand { get; init; } = new(ToggleGallery);
-    public required ReactiveCommand ToggleBottomGalleryCommand { get; init; } = new(ToggleBottomGallery);
-    public required ReactiveCommand CloseGalleryCommand { get; init; } = new(CloseGallery);
-    public required ReactiveCommand<string> GalleryItemStretchCommand { get; init; } = new(GalleryItemStretch);
+    public ReactiveCommand ToggleGalleryCommand { get; init; } = new(ToggleGallery);
+    public ReactiveCommand ToggleBottomGalleryCommand { get; init; } = new(ToggleBottomGallery);
+    public ReactiveCommand CloseGalleryCommand { get; init; } = new(CloseGallery);
+    public ReactiveCommand<string> GalleryItemStretchCommand { get; init; } = new(GalleryItemStretch);
 
     private static void ToggleGallery(Unit unit) => FunctionsMapper.ToggleGallery();
     private static void ToggleBottomGallery(Unit unit) => FunctionsMapper.OpenCloseBottomGallery();
@@ -85,7 +84,6 @@ public class GalleryViewModel : IDisposable
     {
         Disposable.Dispose(GalleryItem,
             GalleryMargin,
-            GalleryWidth,
             IsBottomGalleryShown,
             IsBottomGalleryShownInHiddenUI,
             GalleryMode,

+ 1 - 251
src/PicView.Avalonia/ViewModels/MainViewModel.cs

@@ -32,6 +32,7 @@ public class MainViewModel : ReactiveObject
     public readonly IPlatformWindowService? PlatformWindowService;
     
     public TranslationViewModel Translation { get; } = new();
+    public GlobalSettingsViewModel? GLobalSettings { get; } = new();
     public SettingsViewModel? SettingsViewModel { get; set; }
     public ImageCropperViewModel? Crop { get; set; }
     public PicViewerModel PicViewer { get; } = new();
@@ -290,257 +291,6 @@ public class MainViewModel : ReactiveObject
         // Only use for unit test
     }
 
-    #region Gallery
-
-    public Thickness GalleryMargin
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsBottomGalleryShown
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsBottomGalleryShownInHiddenUI
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public GalleryMode GalleryMode
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    } = GalleryMode.Closed;
-
-    public Stretch GalleryStretch
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public int SelectedGalleryItemIndex
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public VerticalAlignment GalleryVerticalAlignment
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    } = VerticalAlignment.Bottom;
-
-    public Orientation GalleryOrientation
-    {
-        set => this.RaiseAndSetIfChanged(ref field, value);
-        get;
-    }
-
-    public bool IsFullGalleryOpen
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public double GalleryWidth
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public double GalleryHeight
-    {
-        get
-        {
-            if (!Settings.Gallery.IsBottomGalleryShown || IsSingleImage || Slideshow.IsRunning)
-            {
-                return 0;
-            }
-
-            if (Settings.WindowProperties.Fullscreen)
-            {
-                return Settings.Gallery.IsBottomGalleryShown
-                    ? GetBottomGalleryItemHeight + (SizeDefaults.ScrollbarSize - 1)
-                    : 0;
-            }
-
-            if (!Settings.Gallery.ShowBottomGalleryInHiddenUI && !IsUIShown)
-            {
-                return 0;
-            }
-
-            return GetBottomGalleryItemHeight + (SizeDefaults.ScrollbarSize - 1);
-        }
-    }
-
-    public double GetGalleryItemWidth
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    } = double.NaN;
-
-    public double GetGalleryItemHeight
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public double GetFullGalleryItemHeight
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public double GetBottomGalleryItemHeight
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public double MaxFullGalleryItemHeight
-    {
-        get => GalleryDefaults.MaxFullGalleryItemHeight;
-    }
-
-    public double MinFullGalleryItemHeight
-    {
-        get => GalleryDefaults.MinFullGalleryItemHeight;
-    }
-
-    public double MaxBottomGalleryItemHeight
-    {
-        get => GalleryDefaults.MaxBottomGalleryItemHeight;
-    }
-
-    public double MinBottomGalleryItemHeight
-    {
-        get => GalleryDefaults.MinBottomGalleryItemHeight;
-    }
-
-    public Thickness GalleryItemMargin
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    #region Gallery Stretch IsChecked
-
-    public bool IsUniformBottomChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsUniformFullChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsUniformMenuChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsUniformToFillBottomChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsUniformToFillFullChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsUniformToFillMenuChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsFillBottomChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsFillFullChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsFillMenuChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsNoneBottomChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsNoneFullChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsNoneMenuChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsSquareBottomChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsSquareFullChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsSquareMenuChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsFillSquareBottomChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsFillSquareFullChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    public bool IsFillSquareMenuChecked
-    {
-        get;
-        set => this.RaiseAndSetIfChanged(ref field, value);
-    }
-
-    #endregion
-
-    #endregion Gallery
-
     #region Commands
 
     public ReactiveCommand<Unit, Unit>? ExitCommand { get; }

+ 3 - 3
src/PicView.Avalonia/Views/GallerySettingsView.axaml

@@ -52,7 +52,7 @@
             BorderThickness="0"
             Classes="altHover changeColor"
             Command="{CompiledBinding ToggleBottomGalleryShownInHiddenUICommand}"
-            IsChecked="{CompiledBinding IsBottomGalleryShownInHiddenUI}"
+            IsChecked="{CompiledBinding SettingsViewModel.IsBottomGalleryShownInHiddenUI}"
             Margin="0,0,0,10"
             Width="300">
             <TextBlock
@@ -77,7 +77,7 @@
             FontFamily="/Assets/Fonts/Roboto-Bold.ttf#Roboto"
             Foreground="{DynamicResource MainTextColorFaded}"
             Margin="0,0,0,15"
-            Text="{CompiledBinding GetFullGalleryItemHeight,
+            Text="{CompiledBinding Gallery.GalleryItem.ExpandedGalleryItemHeight,
                                    Mode=OneWay}" />
 
         <TextBlock
@@ -94,7 +94,7 @@
             FontFamily="/Assets/Fonts/Roboto-Bold.ttf#Roboto"
             Foreground="{DynamicResource MainTextColorFaded}"
             Margin="0,0,0,15"
-            Text="{CompiledBinding GetBottomGalleryItemHeight,
+            Text="{CompiledBinding Gallery.GalleryItem.BottomGalleryItemHeight,
                                    Mode=OneWay}" />
 
         <TextBlock

+ 13 - 13
src/PicView.Avalonia/Views/GalleryView.axaml

@@ -33,42 +33,42 @@
                         CommandParameter="Uniform"
                         Header="{CompiledBinding Translation.Uniform.Value,
                                                  Mode=OneWay}"
-                        IsChecked="{CompiledBinding IsUniformMenuChecked}"
+                        IsChecked="{CompiledBinding Gallery.IsUniformMenuChecked.Value}"
                         ToggleType="Radio" />
                     <MenuItem
                         Command="{CompiledBinding GalleryItemStretchCommand}"
                         CommandParameter="UniformToFill"
                         Header="{CompiledBinding Translation.UniformToFill.Value,
                                                  Mode=OneWay}"
-                        IsChecked="{CompiledBinding IsUniformToFillMenuChecked}"
+                        IsChecked="{CompiledBinding Gallery.IsUniformToFillMenuChecked.Value}"
                         ToggleType="Radio" />
                     <MenuItem
                         Command="{CompiledBinding GalleryItemStretchCommand}"
                         CommandParameter="Fill"
                         Header="{CompiledBinding Translation.Fill.Value,
                                                  Mode=OneWay}"
-                        IsChecked="{CompiledBinding IsFillMenuChecked}"
+                        IsChecked="{CompiledBinding Gallery.IsFillMenuChecked.Value}"
                         ToggleType="Radio" />
                     <MenuItem
                         Command="{CompiledBinding GalleryItemStretchCommand}"
                         CommandParameter="None"
                         Header="{CompiledBinding Translation.None.Value,
                                                  Mode=OneWay}"
-                        IsChecked="{CompiledBinding IsNoneMenuChecked}"
+                        IsChecked="{CompiledBinding Gallery.IsNoneMenuChecked.Value}"
                         ToggleType="Radio" />
                     <MenuItem
                         Command="{CompiledBinding GalleryItemStretchCommand}"
                         CommandParameter="Square"
                         Header="{CompiledBinding Translation.Square.Value,
                                                  Mode=OneWay}"
-                        IsChecked="{CompiledBinding IsSquareMenuChecked}"
+                        IsChecked="{CompiledBinding Gallery.IsSquareMenuChecked.Value}"
                         ToggleType="Radio" />
                     <MenuItem
                         Command="{CompiledBinding GalleryItemStretchCommand}"
                         CommandParameter="FillSquare"
                         Header="{CompiledBinding Translation.FillSquare.Value,
                                                  Mode=OneWay}"
-                        IsChecked="{CompiledBinding IsFillSquareMenuChecked}"
+                        IsChecked="{CompiledBinding Gallery.IsFillSquareMenuChecked.Value}"
                         ToggleType="Radio" />
                 </MenuItem>
                 <MenuItem
@@ -100,7 +100,7 @@
                     Command="{CompiledBinding CloseGalleryCommand}"
                     Header="{CompiledBinding Translation.HideBottomGallery.Value,
                                              Mode=OneWay}"
-                    IsVisible="{CompiledBinding !IsFullGalleryOpen}">
+                    IsVisible="{CompiledBinding !Gallery.IsGalleryExpanded.Value}">
                     <MenuItem.Icon>
                         <Path
                             Data="{StaticResource CloseGeometry}"
@@ -114,7 +114,7 @@
                     Command="{CompiledBinding ToggleGalleryCommand}"
                     Header="{CompiledBinding Translation.CloseGallery.Value,
                                              Mode=OneWay}"
-                    IsVisible="{CompiledBinding IsFullGalleryOpen}">
+                    IsVisible="{CompiledBinding Gallery.IsGalleryExpanded.Value}">
                     <MenuItem.Icon>
                         <Path
                             Data="{StaticResource CloseGeometry}"
@@ -135,7 +135,7 @@
             DockPanel.Dock="Right"
             Height="60"
             HorizontalAlignment="Right"
-            IsVisible="{CompiledBinding IsFullGalleryOpen}"
+            IsVisible="{CompiledBinding Gallery.IsGalleryExpanded.Value}"
             VerticalAlignment="Top"
             Width="50"
             ZIndex="99">
@@ -158,21 +158,21 @@
             ScrollViewer.HorizontalScrollBarVisibility="Visible"
             ScrollViewer.IsScrollInertiaEnabled="True"
             ScrollViewer.VerticalScrollBarVisibility="Disabled"
-            SelectedIndex="{CompiledBinding SelectedGalleryItemIndex}"
-            VerticalAlignment="{CompiledBinding GalleryVerticalAlignment}"
+            SelectedIndex="{CompiledBinding PicViewer.Index.Value}"
+            VerticalAlignment="{CompiledBinding Gallery.GalleryVerticalAlignment.Value}"
             x:Name="GalleryListBox">
             <ListBox.ItemsPanel>
                 <ItemsPanelTemplate>
                     <WrapPanel
                         HorizontalAlignment="Left"
-                        Orientation="{CompiledBinding GalleryOrientation,
+                        Orientation="{CompiledBinding Gallery.GalleryOrientation.Value,
                                                       Mode=OneWay}"
                         VerticalAlignment="Center" />
                 </ItemsPanelTemplate>
             </ListBox.ItemsPanel>
             <ListBox.Styles>
                 <Style Selector="ListBoxItem">
-                    <Setter Property="Margin" Value="{CompiledBinding GalleryItemMargin}" />
+                    <Setter Property="Margin" Value="{CompiledBinding Gallery.GalleryItem.ItemMargin.Value}" />
                 </Style>
             </ListBox.Styles>
         </customControls:GalleryListBox>

+ 6 - 6
src/PicView.Avalonia/Views/MainView.axaml

@@ -460,7 +460,7 @@
                     Command="{CompiledBinding ToggleBottomGalleryCommand}"
                     Header="{CompiledBinding Translation.IsShowingBottomGallery.Value,
                                              Mode=OneWay}"
-                    IsChecked="{CompiledBinding IsBottomGalleryShown}">
+                    IsChecked="{CompiledBinding GLobalSettings.IsBottomGalleryShown}">
                     <MenuItem.Icon>
                         <Image Height="12" Width="12">
                             <DrawingImage>
@@ -1091,7 +1091,7 @@
             ClipToBounds="True"
             Content="{CompiledBinding CurrentView,
                                       Mode=OneWay}"
-            Margin="{CompiledBinding GalleryMargin}" />
+            Margin="{CompiledBinding Gallery.GalleryMargin.Value}" />
         <buttons:ClickArrowRight
             HorizontalAlignment="Right"
             Margin="{CompiledBinding RightControlOffSetMargin}"
@@ -1123,14 +1123,14 @@
             VerticalAlignment="Bottom"
             x:Name="GalleryShortcut" />
         <views:GalleryAnimationControlView
-            GalleryMode="{CompiledBinding GalleryMode,
+            GalleryMode="{CompiledBinding Gallery.GalleryMode.Value,
                                           Mode=OneWay}"
             Height="NaN"
-            IsVisible="{CompiledBinding IsBottomGalleryShown,
+            IsVisible="{CompiledBinding GLobalSettings.IsBottomGalleryShown.Value,
                                         Mode=OneWay}"
-            VerticalAlignment="{CompiledBinding GalleryVerticalAlignment,
+            VerticalAlignment="{CompiledBinding Gallery.GalleryVerticalAlignment.Value,
                                                 Mode=OneWay}"
-            Width="{CompiledBinding GalleryWidth,
+            Width="{CompiledBinding PicViewer.GalleryWidth.Value,
                                     Mode=OneWay}"
             x:Name="GalleryView" />
         <uc:ToolTipMessage

+ 3 - 3
src/PicView.Avalonia/Views/UC/BottomGalleryItemSizeSlider.axaml

@@ -15,11 +15,11 @@
         HorizontalAlignment="Center"
         IsSnapToTickEnabled="True"
         Margin="0,1,0,1"
-        Maximum="{CompiledBinding MaxBottomGalleryItemHeight}"
-        Minimum="{CompiledBinding MinBottomGalleryItemHeight}"
+        Maximum="{CompiledBinding Gallery.GalleryItem.MaxExpandedGalleryItemHeight}"
+        Minimum="{CompiledBinding Gallery.GalleryItem.MinExpandedGalleryItemHeight}"
         TickFrequency="1"
         TickPlacement="BottomRight"
-        Value="{CompiledBinding GetBottomGalleryItemHeight,
+        Value="{CompiledBinding Gallery.GalleryItem.ItemHeight.Value,
                                 Mode=OneWay}"
         ValueChanged="BottomGallery_OnValueChanged"
         Width="300" />

+ 4 - 4
src/PicView.Avalonia/Views/UC/BottomGalleryItemSizeSlider.axaml.cs

@@ -20,16 +20,16 @@ public partial class BottomGalleryItemSizeSlider : UserControl
             return;
         }
         // ReSharper disable once CompareOfFloatsByEqualityOperator
-        if (vm.GetBottomGalleryItemHeight == e.NewValue)
+        if (vm.Gallery.GalleryItem.BottomGalleryItemHeight.CurrentValue == e.NewValue)
         {
             return;
         }
-        vm.GetBottomGalleryItemHeight = e.NewValue;
+        vm.Gallery.GalleryItem.BottomGalleryItemHeight.Value = e.NewValue;
         
         if (Settings.Gallery.IsBottomGalleryShown && !GalleryFunctions.IsFullGalleryOpen)
         {
-            vm.GetGalleryItemHeight = e.NewValue;
-            UIHelper.GetGalleryView.Height = vm.GalleryHeight;
+            vm.Gallery.GalleryItem.ItemHeight.Value= e.NewValue;
+            UIHelper.GetGalleryView.Height = GalleryFunctions.GetGalleryHeight(vm);
             WindowResizing.SetSize(vm);
         }
         

+ 1 - 1
src/PicView.Avalonia/Views/UC/Buttons/GalleryShortcut.axaml

@@ -1,7 +1,7 @@
 <UserControl
     Background="Transparent"
     Height="210"
-    IsEnabled="{CompiledBinding !IsBottomGalleryShown}"
+    IsEnabled="{CompiledBinding !Gallery.IsBottomGalleryShown.Value}"
     IsVisible="{CompiledBinding !IsUIShown}"
     Width="210"
     d:DesignHeight="450"

+ 3 - 3
src/PicView.Avalonia/Views/UC/FullGalleryItemSizeSlider.axaml

@@ -15,11 +15,11 @@
         HorizontalAlignment="Center"
         IsSnapToTickEnabled="True"
         Margin="0,1,0,1"
-        Maximum="{CompiledBinding MaxFullGalleryItemHeight}"
-        Minimum="{CompiledBinding MinFullGalleryItemHeight}"
+        Maximum="{CompiledBinding Gallery.GalleryItem.MaxExpandedGalleryItemHeight}"
+        Minimum="{CompiledBinding Gallery.GalleryItem.MinExpandedGalleryItemHeight}"
         TickFrequency="1"
         TickPlacement="BottomRight"
-        Value="{CompiledBinding GetFullGalleryItemHeight,
+        Value="{CompiledBinding Gallery.GalleryItem.ExpandedGalleryItemHeight.Value,
                                 Mode=OneWay}"
         ValueChanged="FullGallery_OnValueChanged"
         Width="300" />

+ 3 - 3
src/PicView.Avalonia/Views/UC/FullGalleryItemSizeSlider.axaml.cs

@@ -20,14 +20,14 @@ public partial class FullGalleryItemSizeSlider : UserControl
         }
 
         // ReSharper disable once CompareOfFloatsByEqualityOperator
-        if (vm.GetFullGalleryItemHeight == e.NewValue)
+        if (vm.Gallery.GalleryItem.ExpandedGalleryItemHeight.CurrentValue == e.NewValue)
         {
             return;
         }
-        vm.GetFullGalleryItemHeight = e.NewValue;
+        vm.Gallery.GalleryItem.ExpandedGalleryItemHeight.Value = e.NewValue;
         if (GalleryFunctions.IsFullGalleryOpen)
         {
-            vm.GetGalleryItemHeight = vm.GetFullGalleryItemHeight;
+            vm.Gallery.GalleryItem.ItemHeight.Value = e.NewValue;
             WindowResizing.SetSize(vm);
         }
         // Binding to height depends on timing of the update. Maybe find a cleaner mvvm solution one day

+ 11 - 11
src/PicView.Avalonia/Views/UC/GalleryItem.axaml

@@ -14,17 +14,17 @@
     <Border
         Background="Transparent"
         BorderThickness="2"
-        Height="{CompiledBinding GetGalleryItemHeight,
+        Height="{CompiledBinding Gallery.GalleryItem.ItemHeight.Value,
                                  Mode=OneWay}"
         MinWidth="25"
         ToolTip.HorizontalOffset="0"
         ToolTip.Placement="TopEdgeAlignedLeft"
         ToolTip.VerticalOffset="0"
-        Width="{CompiledBinding GetGalleryItemWidth,
+        Width="{CompiledBinding Gallery.GalleryItem.ItemWidth.Value,
                                 Mode=OneWay}"
         x:DataType="viewModels:MainViewModel"
         x:Name="ImageBorder">
-        <customControls:ThumbImage Stretch="{CompiledBinding GalleryStretch, Mode=OneWay}" x:Name="GalleryImage" />
+        <customControls:ThumbImage Stretch="{CompiledBinding Gallery.GalleryStretch.Value, Mode=OneWay}" x:Name="GalleryImage" />
         <ToolTip.Tip>
             <StackPanel MaxWidth="600">
                 <TextBlock
@@ -207,42 +207,42 @@
                         CommandParameter="Uniform"
                         Header="{CompiledBinding Translation.Uniform.Value,
                                                  Mode=OneWay}"
-                        IsChecked="{CompiledBinding IsUniformMenuChecked}"
+                        IsChecked="{CompiledBinding Gallery.IsUniformMenuChecked.Value}"
                         ToggleType="Radio" />
                     <MenuItem
                         Command="{CompiledBinding GalleryItemStretchCommand}"
                         CommandParameter="UniformToFill"
                         Header="{CompiledBinding Translation.UniformToFill.Value,
                                                  Mode=OneWay}"
-                        IsChecked="{CompiledBinding IsUniformToFillMenuChecked}"
+                        IsChecked="{CompiledBinding Gallery.IsUniformToFillMenuChecked.Value}"
                         ToggleType="Radio" />
                     <MenuItem
                         Command="{CompiledBinding GalleryItemStretchCommand}"
                         CommandParameter="Fill"
                         Header="{CompiledBinding Translation.Fill.Value,
                                                  Mode=OneWay}"
-                        IsChecked="{CompiledBinding IsFillMenuChecked}"
+                        IsChecked="{CompiledBinding Gallery.IsFillMenuChecked.Value}"
                         ToggleType="Radio" />
                     <MenuItem
                         Command="{CompiledBinding GalleryItemStretchCommand}"
                         CommandParameter="None"
                         Header="{CompiledBinding Translation.None.Value,
                                                  Mode=OneWay}"
-                        IsChecked="{CompiledBinding IsNoneMenuChecked}"
+                        IsChecked="{CompiledBinding Gallery.IsNoneMenuChecked.Value}"
                         ToggleType="Radio" />
                     <MenuItem
                         Command="{CompiledBinding GalleryItemStretchCommand}"
                         CommandParameter="Square"
                         Header="{CompiledBinding Translation.Square.Value,
                                                  Mode=OneWay}"
-                        IsChecked="{CompiledBinding IsSquareMenuChecked}"
+                        IsChecked="{CompiledBinding Gallery.IsSquareMenuChecked.Value}"
                         ToggleType="Radio" />
                     <MenuItem
                         Command="{CompiledBinding GalleryItemStretchCommand}"
                         CommandParameter="FillSquare"
                         Header="{CompiledBinding Translation.FillSquare.Value,
                                                  Mode=OneWay}"
-                        IsChecked="{CompiledBinding IsFillSquareMenuChecked}"
+                        IsChecked="{CompiledBinding Gallery.IsFillSquareMenuChecked.Value}"
                         ToggleType="Radio" />
                 </MenuItem>
                 <MenuItem
@@ -274,7 +274,7 @@
                     Command="{CompiledBinding CloseGalleryCommand}"
                     Header="{CompiledBinding Translation.HideBottomGallery.Value,
                                              Mode=OneWay}"
-                    IsVisible="{CompiledBinding !IsFullGalleryOpen}">
+                    IsVisible="{CompiledBinding !Gallery.IsGalleryExpanded.Value}">
                     <MenuItem.Icon>
                         <Path
                             Data="{StaticResource CloseGeometry}"
@@ -288,7 +288,7 @@
                     Command="{CompiledBinding ToggleGalleryCommand}"
                     Header="{CompiledBinding Translation.CloseGallery.Value,
                                              Mode=OneWay}"
-                    IsVisible="{CompiledBinding IsFullGalleryOpen}">
+                    IsVisible="{CompiledBinding Gallery.IsGalleryExpanded.Value}">
                     <MenuItem.Icon>
                         <Path
                             Data="{StaticResource CloseGeometry}"

+ 1 - 1
src/PicView.Avalonia/Views/UC/GalleryItemSizeSlider.axaml

@@ -17,7 +17,7 @@
         Margin="0,1,0,1"
         TickFrequency="1"
         TickPlacement="BottomRight"
-        Value="{CompiledBinding GetGalleryItemHeight,
+        Value="{CompiledBinding Gallery.GalleryItem.ItemHeight.Value,
                                 Mode=OneWay}"
         ValueChanged="RangeBase_OnValueChanged"
         Width="270"

+ 19 - 14
src/PicView.Avalonia/Views/UC/GalleryItemSizeSlider.axaml.cs

@@ -4,6 +4,7 @@ using PicView.Avalonia.Gallery;
 using PicView.Avalonia.UI;
 using PicView.Avalonia.ViewModels;
 using PicView.Avalonia.WindowBehavior;
+using PicView.Core.Gallery;
 
 namespace PicView.Avalonia.Views.UC;
 
@@ -12,7 +13,6 @@ public partial class GalleryItemSizeSlider : UserControl
     public GalleryItemSizeSlider()
     {
         InitializeComponent();
-        
     }
     
     public void SetMaxAndMin()
@@ -21,15 +21,17 @@ public partial class GalleryItemSizeSlider : UserControl
         {
             return;
         }
+
+        vm.Gallery ??= new GalleryViewModel();
         if (GalleryFunctions.IsFullGalleryOpen)
         {
-            CustomSlider.Maximum = vm.MaxFullGalleryItemHeight;
-            CustomSlider.Minimum = vm.MinFullGalleryItemHeight;
+            CustomSlider.Maximum = GalleryDefaults.MaxFullGalleryItemHeight;
+            CustomSlider.Minimum = GalleryDefaults.MinBottomGalleryItemHeight;
         }
         else
         {
-            CustomSlider.Maximum = vm.MaxBottomGalleryItemHeight;
-            CustomSlider.Minimum = vm.MinBottomGalleryItemHeight;
+            CustomSlider.Maximum = GalleryDefaults.MaxBottomGalleryItemHeight;
+            CustomSlider.Minimum = GalleryDefaults.MinBottomGalleryItemHeight;
         }
     }
 
@@ -40,17 +42,19 @@ public partial class GalleryItemSizeSlider : UserControl
             return;
         }
 
+        vm.Gallery ??= new GalleryViewModel();
+
         if (GalleryFunctions.IsFullGalleryOpen)
         {
             // ReSharper disable once CompareOfFloatsByEqualityOperator
-            if (vm.GetFullGalleryItemHeight == e.NewValue)
+            if (vm.Gallery.GalleryItem.ItemHeight.CurrentValue == e.NewValue)
             {
                 return;
             }
-            vm.GetFullGalleryItemHeight = e.NewValue;
-            vm.GetGalleryItemHeight = vm.GetFullGalleryItemHeight;
+            vm.Gallery.GalleryItem.ExpandedGalleryItemHeight.Value = e.NewValue;
+            
             WindowResizing.SetSize(vm);
-            // Binding to height depends on timing of the update. Maybe find a cleaner mvvm solution one day
+            // TODO: Binding to height depends on timing of the update. Maybe find a cleaner mvvm solution one day
         
             // Maybe save this on close or some other way
             Settings.Gallery.ExpandedGalleryItemSize = e.NewValue;
@@ -59,20 +63,21 @@ public partial class GalleryItemSizeSlider : UserControl
         else if (Settings.Gallery.IsBottomGalleryShown)
         {
             // ReSharper disable once CompareOfFloatsByEqualityOperator
-            if (vm.GetBottomGalleryItemHeight == e.NewValue)
+            if (vm.Gallery.GalleryItem.BottomGalleryItemHeight.CurrentValue == e.NewValue)
             {
                 return;
             }
-            vm.GetBottomGalleryItemHeight = e.NewValue;
-        
-            vm.GetGalleryItemHeight = e.NewValue;
-            UIHelper.GetGalleryView.Height = vm.GalleryHeight;
+            vm.Gallery.GalleryItem.BottomGalleryItemHeight.Value = e.NewValue;
+            
+            UIHelper.GetGalleryView.Height = GalleryFunctions.GetGalleryHeight(vm);
             WindowResizing.SetSize(vm);
         
             // Binding to height depends on timing of the update. Maybe find a cleaner mvvm solution one day
             // Maybe save this on close or some other way
             Settings.Gallery.BottomGalleryItemSize = e.NewValue;
         }
+        
+        vm.Gallery.GalleryItem.ItemHeight.Value = e.NewValue;
        
         _ = SaveSettingsAsync();
     }

+ 13 - 8
src/PicView.Avalonia/WindowBehavior/WindowResizing.cs

@@ -4,6 +4,7 @@ using Avalonia.Controls.ApplicationLifetimes;
 using Avalonia.Media.Imaging;
 using Avalonia.Threading;
 using ImageMagick;
+using PicView.Avalonia.Gallery;
 using PicView.Avalonia.Navigation;
 using PicView.Avalonia.UI;
 using PicView.Avalonia.ViewModels;
@@ -102,32 +103,36 @@ public static class WindowResizing
         vm.PicViewer.ImageWidth.Value = size.Width;
         vm.PicViewer.SecondaryImageWidth.Value = size.SecondaryWidth;
         vm.PicViewer.ImageHeight.Value = size.Height;
-        vm.GalleryMargin = new Thickness(0, 0, 0, size.Margin);
 
         vm.PicViewer.ScrollViewerWidth.Value = size.ScrollViewerWidth;
         vm.PicViewer.ScrollViewerHeight.Value = size.ScrollViewerHeight;
+        
+        vm.PicViewer.AspectRatio.Value = size.AspectRatio;
 
+        if (vm.Gallery is not { } gallery)
+        {
+            return;
+        }
+        gallery.GalleryMargin.Value = new Thickness(0, 0, 0, size.Margin);
         if (Settings.WindowProperties.AutoFit)
         {
             if (Settings.WindowProperties.Fullscreen ||
                 Settings.WindowProperties.Maximized)
             {
-                vm.GalleryWidth = double.NaN;
+                vm.PicViewer.GalleryWidth.Value = double.NaN;
             }
             else
             {
                 var scrollbarSize = Settings.Zoom.ScrollEnabled ? SizeDefaults.ScrollbarSize : 0;
-                vm.GalleryWidth = vm.RotationAngle is 90 or 270
+                vm.PicViewer.GalleryWidth.Value = vm.RotationAngle is 90 or 270
                     ? Math.Max(size.Height + scrollbarSize, SizeDefaults.WindowMinSize + scrollbarSize)
                     : Math.Max(size.Width + scrollbarSize, SizeDefaults.WindowMinSize + scrollbarSize);
             }
         }
         else
         {
-            vm.GalleryWidth = double.NaN;
+            vm.PicViewer.GalleryWidth.Value = double.NaN;
         }
-
-        vm.PicViewer.AspectRatio.Value = size.AspectRatio;
     }
 
     public static ImageSize? GetSize(MainViewModel vm)
@@ -248,7 +253,7 @@ public static class WindowResizing
                 screenSize.Scaling,
                 vm.TitlebarHeight,
                 vm.BottombarHeight,
-                vm.GalleryHeight,
+                GalleryFunctions.GetGalleryHeight(vm),
                 containerWidth,
                 containerHeight);
         }
@@ -265,7 +270,7 @@ public static class WindowResizing
                 screenSize.Scaling,
                 vm.TitlebarHeight,
                 vm.BottombarHeight,
-                vm.GalleryHeight,
+                GalleryFunctions.GetGalleryHeight(vm),
                 containerWidth,
                 containerHeight);
         }

+ 14 - 0
src/PicView.Core/ViewModels/GlobalSettingsViewModel.cs

@@ -0,0 +1,14 @@
+using R3;
+
+namespace PicView.Core.ViewModels;
+
+public class GlobalSettingsViewModel : IDisposable
+{
+    public BindableReactiveProperty<bool> IsBottomGalleryShown { get; } = new(Settings.Gallery.IsBottomGalleryShown);
+    public BindableReactiveProperty<bool> ShowBottomGalleryInHiddenUI { get; } = new(Settings.Gallery.ShowBottomGalleryInHiddenUI);
+
+    public void Dispose()
+    {
+        Disposable.Dispose(IsBottomGalleryShown);
+    }
+}

+ 8 - 4
src/PicView.Core/ViewModels/PicViewerModel.cs

@@ -11,7 +11,7 @@ public class PicViewerModel : IDisposable
         Disposable.Dispose(FileInfo, PixelWidth, PixelHeight, ImageSource, SecondaryImageSource, ImageType);
         Disposable.Dispose(ImageType, ImageWidth, ImageHeight, SecondaryImageWidth, IsShowingSideBySide, ScrollViewerHeight);
         Disposable.Dispose(ScrollViewerHeight, AspectRatio, EffectConfig, ExifOrientation, ScaleX, Title);
-        Disposable.Dispose(TitleTooltip, WindowTitle);
+        Disposable.Dispose(TitleTooltip, WindowTitle, Index);
     }
     
     public BindableReactiveProperty<FileInfo?> FileInfo { get; } = new();
@@ -49,6 +49,8 @@ public class PicViewerModel : IDisposable
     public BindableReactiveProperty<double> ScrollViewerWidth { get; } = new(0);
 
     public BindableReactiveProperty<double> ScrollViewerHeight { get; } = new(0);
+    
+    public BindableReactiveProperty<double> GalleryWidth { get; } = new(0);
 
     public BindableReactiveProperty<double> AspectRatio { get; } = new();
 
@@ -59,9 +61,11 @@ public class PicViewerModel : IDisposable
     // Used to flip the flip button
     public BindableReactiveProperty<int> ScaleX { get; } = new();
 
-    public BindableReactiveProperty<string?> Title { get; } = new();
+    public BindableReactiveProperty<string> Title { get; } = new();
 
-    public BindableReactiveProperty<string?> TitleTooltip { get; } = new();
+    public BindableReactiveProperty<string> TitleTooltip { get; } = new();
 
-    public BindableReactiveProperty<string?> WindowTitle { get; } = new();
+    public BindableReactiveProperty<string> WindowTitle { get; } = new();
+    
+    public BindableReactiveProperty<int> Index { get; } = new();
 }

+ 4 - 0
src/PicView.Core/ViewModels/SettingsViewModel.cs

@@ -38,6 +38,10 @@ public class SettingsViewModel : IDisposable
 
     public BindableReactiveProperty<bool> IsShowingPermanentDeletionDialog { get; } =
         new(Settings.UIProperties.ShowPermanentDeletionConfirmation);
+    
+    public BindableReactiveProperty<bool> IsBottomGalleryShownInHiddenUI { get; } =
+        new(Settings.Gallery.ShowBottomGalleryInHiddenUI);
+    
 
     #endregion
 }