Przeglądaj źródła

Fix various sync bugs related to palettes

Equbuxu 3 lat temu
rodzic
commit
d61e524424

+ 151 - 116
PixiEditor/Models/DataProviders/LocalPalettesFetcher.cs

@@ -2,56 +2,55 @@
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DataHolders.Palettes;
 using PixiEditor.Models.DataHolders.Palettes;
 using PixiEditor.Models.IO;
 using PixiEditor.Models.IO;
+using PixiEditor.Models.IO.JascPalFile;
+using PixiEditor.Models.UserPreferences;
+using SkiaSharp;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using PixiEditor.Models.IO.JascPalFile;
-using PixiEditor.Models.UserPreferences;
-using SkiaSharp;
 
 
 namespace PixiEditor.Models.DataProviders
 namespace PixiEditor.Models.DataProviders
 {
 {
     public delegate void CacheUpdate(RefreshType refreshType, Palette itemAffected, string oldName);
     public delegate void CacheUpdate(RefreshType refreshType, Palette itemAffected, string oldName);
-        
+
     public class LocalPalettesFetcher : PaletteListDataSource
     public class LocalPalettesFetcher : PaletteListDataSource
     {
     {
         public static string PathToPalettesFolder { get; } = Path.Join(
         public static string PathToPalettesFolder { get; } = Path.Join(
             Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
             Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
             "PixiEditor", "Palettes");
             "PixiEditor", "Palettes");
 
 
-        public List<Palette> CachedPalettes { get; private set; }
+        private List<Palette> cachedPalettes;
+
+        public event CacheUpdate CacheUpdated;
 
 
-        public event CacheUpdate CacheUpdated; 
-        
-        private List<string> _cachedFavoritePalettes;
+        private List<string> cachedFavoritePalettes;
 
 
-        private FileSystemWatcher _watcher;
-        
+        private FileSystemWatcher watcher;
 
 
         public override void Initialize()
         public override void Initialize()
         {
         {
             InitDir();
             InitDir();
-            _watcher = new FileSystemWatcher(PathToPalettesFolder);
-            _watcher.Filter = "*.pal";
-            _watcher.Changed += FileSystemChanged;
-            _watcher.Deleted += FileSystemChanged;
-            _watcher.Renamed += RenamedFile;
-            _watcher.Created += FileSystemChanged;
-
-            _watcher.EnableRaisingEvents = true;
-            _cachedFavoritePalettes = IPreferences.Current.GetLocalPreference<List<string>>(PreferencesConstants.FavouritePalettes);
-            
+            watcher = new FileSystemWatcher(PathToPalettesFolder);
+            watcher.Filter = "*.pal";
+            watcher.Changed += FileSystemChanged;
+            watcher.Deleted += FileSystemChanged;
+            watcher.Renamed += RenamedFile;
+            watcher.Created += FileSystemChanged;
+
+            watcher.EnableRaisingEvents = true;
+            cachedFavoritePalettes = IPreferences.Current.GetLocalPreference<List<string>>(PreferencesConstants.FavouritePalettes);
+
             IPreferences.Current.AddCallback(PreferencesConstants.FavouritePalettes, updated =>
             IPreferences.Current.AddCallback(PreferencesConstants.FavouritePalettes, updated =>
             {
             {
-                _cachedFavoritePalettes = (List<string>)updated;
+                cachedFavoritePalettes = (List<string>)updated;
             });
             });
         }
         }
 
 
         public override async Task<PaletteList> FetchPaletteList(int startIndex, int count, FilteringSettings filtering)
         public override async Task<PaletteList> FetchPaletteList(int startIndex, int count, FilteringSettings filtering)
         {
         {
-            if(CachedPalettes == null)
+            if (cachedPalettes == null)
             {
             {
                 await RefreshCacheAll();
                 await RefreshCacheAll();
             }
             }
@@ -61,7 +60,7 @@ namespace PixiEditor.Models.DataProviders
                 Palettes = new WpfObservableRangeCollection<Palette>()
                 Palettes = new WpfObservableRangeCollection<Palette>()
             };
             };
 
 
-            var filteredPalettes = CachedPalettes.Where(filtering.Filter).ToArray();
+            var filteredPalettes = cachedPalettes.Where(filtering.Filter).ToArray();
 
 
             if (startIndex >= filteredPalettes.Length) return result;
             if (startIndex >= filteredPalettes.Length) return result;
 
 
@@ -91,24 +90,122 @@ namespace PixiEditor.Models.DataProviders
         {
         {
             string newName = Path.GetFileNameWithoutExtension(currentName);
             string newName = Path.GetFileNameWithoutExtension(currentName);
 
 
-            while (File.Exists(Path.Join(PathToPalettesFolder, newName + ".pal")))
+            if (File.Exists(Path.Join(PathToPalettesFolder, newName + ".pal")))
             {
             {
-                newName += "(1)";
+                int number = 1;
+                while (true)
+                {
+                    string potentialName = $"{newName} ({number})";
+                    number++;
+                    if (File.Exists(Path.Join(PathToPalettesFolder, potentialName + ".pal")))
+                        continue;
+                    newName = potentialName;
+                    break;
+                }
             }
             }
 
 
             if (appendExtension)
             if (appendExtension)
-            {
                 newName += ".pal";
                 newName += ".pal";
-            }
 
 
             return newName;
             return newName;
         }
         }
 
 
-        public async Task RefreshCache(RefreshType refreshType, string file)
+        public async Task SavePalette(string fileName, SKColor[] colors)
+        {
+            watcher.EnableRaisingEvents = false;
+            string path = Path.Join(PathToPalettesFolder, fileName);
+            InitDir();
+            await JascFileParser.SaveFile(path, new PaletteFileData(colors));
+            watcher.EnableRaisingEvents = true;
+            
+            await RefreshCache(RefreshType.Created, path);
+        }
+
+        public async Task DeletePalette(string name)
+        {
+            if (!Directory.Exists(PathToPalettesFolder)) return;
+            string path = Path.Join(PathToPalettesFolder, name);
+            if (!File.Exists(path)) return;
+
+            watcher.EnableRaisingEvents = false;
+            File.Delete(path);
+            watcher.EnableRaisingEvents = true;
+            
+            await RefreshCache(RefreshType.Deleted, path);
+        }
+
+        public void RenamePalette(string oldFileName, string newFileName)
+        {
+            if (!Directory.Exists(PathToPalettesFolder)) 
+                return;
+            
+            string oldPath = Path.Join(PathToPalettesFolder, oldFileName);
+            string newPath = Path.Join(PathToPalettesFolder, newFileName);
+            if (!File.Exists(oldPath) || File.Exists(newPath)) 
+                return;
+
+            watcher.EnableRaisingEvents = false;
+            File.Move(oldPath, newPath);
+            watcher.EnableRaisingEvents = true;
+
+            RefreshCacheRenamed(newPath, oldPath);
+        }
+
+        public async Task RefreshCacheAll()
+        {
+            string[] files = DirectoryExtensions.GetFiles(
+                PathToPalettesFolder,
+                string.Join("|", AvailableParsers.SelectMany(x => x.SupportedFileExtensions)),
+                SearchOption.TopDirectoryOnly);
+            cachedPalettes = await ParseAll(files);
+            CacheUpdated?.Invoke(RefreshType.All, null, null);
+        }
+
+        private async void FileSystemChanged(object sender, FileSystemEventArgs e)
+        {
+            bool waitableExceptionOccured = false;
+            do
+            {
+                try
+                {
+                    switch (e.ChangeType)
+                    {
+                        case WatcherChangeTypes.Created:
+                            await RefreshCache(RefreshType.Created, e.FullPath);
+                            break;
+                        case WatcherChangeTypes.Deleted:
+                            await RefreshCache(RefreshType.Deleted, e.FullPath);
+                            break;
+                        case WatcherChangeTypes.Changed:
+                            await RefreshCache(RefreshType.Updated, e.FullPath);
+                            break;
+                        case WatcherChangeTypes.Renamed:
+                            // Handled by method below
+                            break;
+                        case WatcherChangeTypes.All:
+                            await RefreshCache(RefreshType.Created, e.FullPath);
+                            break;
+                        default:
+                            throw new ArgumentOutOfRangeException();
+                    }
+
+                    waitableExceptionOccured = false;
+                }
+                catch (IOException)
+                {
+                    waitableExceptionOccured = true;
+                    await Task.Delay(100);
+                }
+
+            }
+            while (waitableExceptionOccured);
+        }
+
+        private async Task RefreshCache(RefreshType refreshType, string file)
         {
         {
             Palette updated = null;
             Palette updated = null;
             string affectedFileName = null;
             string affectedFileName = null;
-            
+
             switch (refreshType)
             switch (refreshType)
             {
             {
                 case RefreshType.All:
                 case RefreshType.All:
@@ -130,26 +227,26 @@ namespace PixiEditor.Models.DataProviders
             CacheUpdated?.Invoke(refreshType, updated, affectedFileName);
             CacheUpdated?.Invoke(refreshType, updated, affectedFileName);
         }
         }
 
 
-        public void RefreshCacheRenamed(string newFilePath, string oldFilePath)
+        private void RefreshCacheRenamed(string newFilePath, string oldFilePath)
         {
         {
             string oldFileName = Path.GetFileName(oldFilePath);
             string oldFileName = Path.GetFileName(oldFilePath);
-            int index = CachedPalettes.FindIndex(p => p.FileName == oldFileName);
+            int index = cachedPalettes.FindIndex(p => p.FileName == oldFileName);
             if (index == -1) return;
             if (index == -1) return;
-            
-            Palette palette = CachedPalettes[index];
+
+            Palette palette = cachedPalettes[index];
             palette.FileName = Path.GetFileName(newFilePath);
             palette.FileName = Path.GetFileName(newFilePath);
             palette.Name = Path.GetFileNameWithoutExtension(newFilePath);
             palette.Name = Path.GetFileNameWithoutExtension(newFilePath);
-            
+
             CacheUpdated?.Invoke(RefreshType.Renamed, palette, oldFileName);
             CacheUpdated?.Invoke(RefreshType.Renamed, palette, oldFileName);
         }
         }
 
 
         private string RefreshCacheDeleted(string filePath)
         private string RefreshCacheDeleted(string filePath)
         {
         {
             string fileName = Path.GetFileName(filePath);
             string fileName = Path.GetFileName(filePath);
-            int index = CachedPalettes.FindIndex(p => p.FileName == fileName);
+            int index = cachedPalettes.FindIndex(p => p.FileName == fileName);
             if (index == -1) return null;
             if (index == -1) return null;
-            
-            CachedPalettes.RemoveAt(index);
+
+            cachedPalettes.RemoveAt(index);
             return fileName;
             return fileName;
         }
         }
 
 
@@ -165,22 +262,22 @@ namespace PixiEditor.Models.DataProviders
                     if (newPalette is { IsCorrupted: false })
                     if (newPalette is { IsCorrupted: false })
                     {
                     {
                         Palette pal = CreatePalette(newPalette, file,
                         Palette pal = CreatePalette(newPalette, file,
-                            _cachedFavoritePalettes?.Contains(newPalette.Title) ?? false);
+                            cachedFavoritePalettes?.Contains(newPalette.Title) ?? false);
                         action(pal);
                         action(pal);
-                        
+
                         return pal;
                         return pal;
                     }
                     }
                 }
                 }
             }
             }
-            
+
             return null;
             return null;
         }
         }
-        
+
         private async Task<Palette> RefreshCacheUpdated(string file)
         private async Task<Palette> RefreshCacheUpdated(string file)
         {
         {
             return await RefreshCacheItem(file, palette =>
             return await RefreshCacheItem(file, palette =>
             {
             {
-                Palette existingPalette = CachedPalettes.FirstOrDefault(x => x.FileName == palette.FileName);
+                Palette existingPalette = cachedPalettes.FirstOrDefault(x => x.FileName == palette.FileName);
                 if (existingPalette != null)
                 if (existingPalette != null)
                 {
                 {
                     existingPalette.Colors = palette.Colors.ToList();
                     existingPalette.Colors = palette.Colors.ToList();
@@ -192,17 +289,16 @@ namespace PixiEditor.Models.DataProviders
 
 
         private async Task<Palette> RefreshCacheAdded(string file)
         private async Task<Palette> RefreshCacheAdded(string file)
         {
         {
-            return await RefreshCacheItem(file, CachedPalettes.Add);
-        }
-
-        public async Task RefreshCacheAll()
-        {
-            string[] files = DirectoryExtensions.GetFiles(
-                PathToPalettesFolder,
-                string.Join("|", AvailableParsers.SelectMany(x => x.SupportedFileExtensions)),
-                SearchOption.TopDirectoryOnly);
-            CachedPalettes = await ParseAll(files);
-            CacheUpdated?.Invoke(RefreshType.All, null, null);
+            return await RefreshCacheItem(file, palette =>
+            {
+                string fileName = Path.GetFileName(file);
+                int index = cachedPalettes.FindIndex(p => p.FileName == fileName);
+                if (index != -1)
+                {
+                    cachedPalettes.RemoveAt(index);
+                }
+                cachedPalettes.Add(palette);
+            });
         }
         }
 
 
         private async Task<List<Palette>> ParseAll(string[] files)
         private async Task<List<Palette>> ParseAll(string[] files)
@@ -216,8 +312,8 @@ namespace PixiEditor.Models.DataProviders
                 var foundParser = AvailableParsers.First(x => x.SupportedFileExtensions.Contains(extension));
                 var foundParser = AvailableParsers.First(x => x.SupportedFileExtensions.Contains(extension));
                 {
                 {
                     PaletteFileData fileData = await foundParser.Parse(file);
                     PaletteFileData fileData = await foundParser.Parse(file);
-                    if(fileData.IsCorrupted) continue;
-                    var palette = CreatePalette(fileData, file, _cachedFavoritePalettes?.Contains(fileData.Title) ?? false);
+                    if (fileData.IsCorrupted) continue;
+                    var palette = CreatePalette(fileData, file, cachedFavoritePalettes?.Contains(fileData.Title) ?? false);
 
 
                     result.Add(palette);
                     result.Add(palette);
                 }
                 }
@@ -239,67 +335,6 @@ namespace PixiEditor.Models.DataProviders
             return palette;
             return palette;
         }
         }
 
 
-        public async Task SavePalette(string fileName, SKColor[] colors)
-        {
-            _watcher.EnableRaisingEvents = false;
-            string path = Path.Join(PathToPalettesFolder, fileName);
-            InitDir();
-            await JascFileParser.SaveFile(path, new PaletteFileData(colors));
-
-            
-            _watcher.EnableRaisingEvents = true;
-            await RefreshCache(RefreshType.Created, path);
-        }
-
-        public void DeletePalette(string name)
-        {
-            if (!Directory.Exists(PathToPalettesFolder)) return;
-            string path = Path.Join(PathToPalettesFolder, name);
-            if (!File.Exists(path)) return;
-
-            File.Delete(path);
-        }
-
-        private async void FileSystemChanged(object sender, FileSystemEventArgs e)
-        {
-            bool waitableExceptionOccured = false;
-            do
-            {
-                try
-                {
-                    switch (e.ChangeType)
-                    {
-                        case WatcherChangeTypes.Created:
-                            await RefreshCache(RefreshType.Created, e.FullPath);
-                            break;
-                        case WatcherChangeTypes.Deleted:
-                            await RefreshCache(RefreshType.Deleted, e.FullPath);
-                            break;
-                        case WatcherChangeTypes.Changed:
-                            await RefreshCache(RefreshType.Updated, e.FullPath);
-                            break;
-                        case WatcherChangeTypes.Renamed:
-                            // Handled by method below
-                            break;
-                        case WatcherChangeTypes.All:
-                            await RefreshCache(RefreshType.Created, e.FullPath);
-                            break;
-                        default:
-                            throw new ArgumentOutOfRangeException();
-                    }
-                    
-                    waitableExceptionOccured = false;
-                }
-                catch(IOException)
-                {
-                    waitableExceptionOccured = true;
-                    await Task.Delay(100);
-                }
-                
-            }
-            while (waitableExceptionOccured);
-        }
-        
         private void RenamedFile(object sender, RenamedEventArgs e)
         private void RenamedFile(object sender, RenamedEventArgs e)
         {
         {
             RefreshCacheRenamed(e.FullPath, e.OldFullPath);
             RefreshCacheRenamed(e.FullPath, e.OldFullPath);

+ 53 - 107
PixiEditor/Views/Dialogs/PalettesBrowser.xaml.cs

@@ -23,112 +23,101 @@ using System.Windows.Navigation;
 
 
 namespace PixiEditor.Views.Dialogs
 namespace PixiEditor.Views.Dialogs
 {
 {
-    public delegate void ListFetched(PaletteList list, int cacheId);
-
-    /// <summary>
-    /// Interaction logic for LospecPalettesBrowser.xaml
-    /// </summary>
     public partial class PalettesBrowser : Window
     public partial class PalettesBrowser : Window
     {
     {
-        public const int ItemsPerLoad = 10;
+        private const int ItemsPerLoad = 10;
 
 
         public PaletteList PaletteList
         public PaletteList PaletteList
         {
         {
-            get { return (PaletteList)GetValue(PaletteListProperty); }
-            set { SetValue(PaletteListProperty, value); }
+            get => (PaletteList)GetValue(PaletteListProperty);
+            set => SetValue(PaletteListProperty, value);
         }
         }
 
 
-        // Using a DependencyProperty as the backing store for PaletteList.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty PaletteListProperty =
         public static readonly DependencyProperty PaletteListProperty =
-            DependencyProperty.Register("PaletteList", typeof(PaletteList), typeof(PalettesBrowser));
+            DependencyProperty.Register(nameof(PaletteList), typeof(PaletteList), typeof(PalettesBrowser));
 
 
         public ICommand ImportPaletteCommand
         public ICommand ImportPaletteCommand
         {
         {
-            get { return (ICommand)GetValue(ImportPaletteCommandProperty); }
-            set { SetValue(ImportPaletteCommandProperty, value); }
+            get => (ICommand)GetValue(ImportPaletteCommandProperty);
+            set => SetValue(ImportPaletteCommandProperty, value);
         }
         }
 
 
-        // Using a DependencyProperty as the backing store for ImportPaletteCommand.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty ImportPaletteCommandProperty =
         public static readonly DependencyProperty ImportPaletteCommandProperty =
-            DependencyProperty.Register("ImportPaletteCommand", typeof(ICommand), typeof(PalettesBrowser));
+            DependencyProperty.Register(nameof(ImportPaletteCommand), typeof(ICommand), typeof(PalettesBrowser));
 
 
         public static readonly DependencyProperty DeletePaletteCommandProperty = DependencyProperty.Register(
         public static readonly DependencyProperty DeletePaletteCommandProperty = DependencyProperty.Register(
-            "DeletePaletteCommand", typeof(ICommand), typeof(PalettesBrowser), new PropertyMetadata(default(ICommand)));
+            nameof(DeletePaletteCommand), typeof(ICommand), typeof(PalettesBrowser), new PropertyMetadata(default(ICommand)));
 
 
         public ICommand DeletePaletteCommand
         public ICommand DeletePaletteCommand
         {
         {
-            get { return (ICommand)GetValue(DeletePaletteCommandProperty); }
-            set { SetValue(DeletePaletteCommandProperty, value); }
+            get => (ICommand)GetValue(DeletePaletteCommandProperty);
+            set => SetValue(DeletePaletteCommandProperty, value);
         }
         }
 
 
         public bool IsFetching
         public bool IsFetching
         {
         {
-            get { return (bool)GetValue(IsFetchingProperty); }
-            set { SetValue(IsFetchingProperty, value); }
+            get => (bool)GetValue(IsFetchingProperty);
+            set => SetValue(IsFetchingProperty, value);
         }
         }
 
 
-        // Using a DependencyProperty as the backing store for IsFetching.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty IsFetchingProperty =
         public static readonly DependencyProperty IsFetchingProperty =
-            DependencyProperty.Register("IsFetching", typeof(bool), typeof(PalettesBrowser), new PropertyMetadata(false));
+            DependencyProperty.Register(nameof(IsFetching), typeof(bool), typeof(PalettesBrowser), new PropertyMetadata(false));
 
 
         public int ColorsNumber
         public int ColorsNumber
         {
         {
-            get { return (int)GetValue(ColorsNumberProperty); }
-            set { SetValue(ColorsNumberProperty, value); }
+            get => (int)GetValue(ColorsNumberProperty);
+            set => SetValue(ColorsNumberProperty, value);
         }
         }
 
 
-        // Using a DependencyProperty as the backing store for ColorsNumber.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty ColorsNumberProperty =
         public static readonly DependencyProperty ColorsNumberProperty =
-            DependencyProperty.Register("ColorsNumber", typeof(int), typeof(PalettesBrowser),
+            DependencyProperty.Register(nameof(ColorsNumber), typeof(int), typeof(PalettesBrowser),
                 new PropertyMetadata(8, ColorsNumberChanged));
                 new PropertyMetadata(8, ColorsNumberChanged));
 
 
         public WpfObservableRangeCollection<PaletteListDataSource> PaletteListDataSources
         public WpfObservableRangeCollection<PaletteListDataSource> PaletteListDataSources
         {
         {
-            get { return (WpfObservableRangeCollection<PaletteListDataSource>)GetValue(PaletteListDataSourcesProperty); }
-            set { SetValue(PaletteListDataSourcesProperty, value); }
+            get => (WpfObservableRangeCollection<PaletteListDataSource>)GetValue(PaletteListDataSourcesProperty);
+            set => SetValue(PaletteListDataSourcesProperty, value);
         }
         }
 
 
-        // Using a DependencyProperty as the backing store for PaletteListDataSources.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty PaletteListDataSourcesProperty =
         public static readonly DependencyProperty PaletteListDataSourcesProperty =
-            DependencyProperty.Register("PaletteListDataSources", typeof(WpfObservableRangeCollection<PaletteListDataSource>), typeof(PalettesBrowser), new PropertyMetadata(new WpfObservableRangeCollection<PaletteListDataSource>()));
+            DependencyProperty.Register(nameof(PaletteListDataSources), typeof(WpfObservableRangeCollection<PaletteListDataSource>), typeof(PalettesBrowser), new PropertyMetadata(new WpfObservableRangeCollection<PaletteListDataSource>()));
         public bool SortAscending
         public bool SortAscending
         {
         {
-            get { return (bool)GetValue(SortAscendingProperty); }
-            set { SetValue(SortAscendingProperty, value); }
+            get => (bool)GetValue(SortAscendingProperty);
+            set => SetValue(SortAscendingProperty, value);
         }
         }
 
 
-        // Using a DependencyProperty as the backing store for SortDescending.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty SortAscendingProperty =
         public static readonly DependencyProperty SortAscendingProperty =
-            DependencyProperty.Register("SortAscending", typeof(bool), typeof(PalettesBrowser), new PropertyMetadata(true, OnSortAscendingChanged));
+            DependencyProperty.Register(nameof(SortAscending), typeof(bool), typeof(PalettesBrowser), new PropertyMetadata(true, OnSortAscendingChanged));
 
 
 
 
         public static readonly DependencyProperty SortedResultsProperty = DependencyProperty.Register(
         public static readonly DependencyProperty SortedResultsProperty = DependencyProperty.Register(
-            "SortedResults", typeof(WpfObservableRangeCollection<Palette>), typeof(PalettesBrowser), new PropertyMetadata(default(WpfObservableRangeCollection<Palette>)));
+            nameof(SortedResults), typeof(WpfObservableRangeCollection<Palette>), typeof(PalettesBrowser), new PropertyMetadata(default(WpfObservableRangeCollection<Palette>)));
 
 
         public WpfObservableRangeCollection<Palette> SortedResults
         public WpfObservableRangeCollection<Palette> SortedResults
         {
         {
-            get { return (WpfObservableRangeCollection<Palette>)GetValue(SortedResultsProperty); }
-            set { SetValue(SortedResultsProperty, value); }
+            get => (WpfObservableRangeCollection<Palette>)GetValue(SortedResultsProperty);
+            set => SetValue(SortedResultsProperty, value);
         }
         }
 
 
         public static readonly DependencyProperty NameFilterProperty = DependencyProperty.Register(
         public static readonly DependencyProperty NameFilterProperty = DependencyProperty.Register(
-            "NameFilter", typeof(string), typeof(PalettesBrowser),
+            nameof(NameFilter), typeof(string), typeof(PalettesBrowser),
             new PropertyMetadata(default(string), OnNameFilterChanged));
             new PropertyMetadata(default(string), OnNameFilterChanged));
 
 
         public string NameFilter
         public string NameFilter
         {
         {
-            get { return (string)GetValue(NameFilterProperty); }
-            set { SetValue(NameFilterProperty, value); }
+            get => (string)GetValue(NameFilterProperty);
+            set => SetValue(NameFilterProperty, value);
         }
         }
 
 
         public static readonly DependencyProperty ShowOnlyFavouritesProperty = DependencyProperty.Register(
         public static readonly DependencyProperty ShowOnlyFavouritesProperty = DependencyProperty.Register(
-            "ShowOnlyFavourites", typeof(bool), typeof(PalettesBrowser),
+            nameof(ShowOnlyFavourites), typeof(bool), typeof(PalettesBrowser),
             new PropertyMetadata(false, OnShowOnlyFavouritesChanged));
             new PropertyMetadata(false, OnShowOnlyFavouritesChanged));
 
 
         public bool ShowOnlyFavourites
         public bool ShowOnlyFavourites
         {
         {
-            get { return (bool)GetValue(ShowOnlyFavouritesProperty); }
-            set { SetValue(ShowOnlyFavouritesProperty, value); }
+            get => (bool)GetValue(ShowOnlyFavouritesProperty);
+            set => SetValue(ShowOnlyFavouritesProperty, value);
         }
         }
 
 
         public RelayCommand<Palette> ToggleFavouriteCommand { get; set; }
         public RelayCommand<Palette> ToggleFavouriteCommand { get; set; }
@@ -151,13 +140,13 @@ namespace PixiEditor.Views.Dialogs
         {
         {
             get
             get
             {
             {
-                return _localPalettesFetcher ??= (LocalPalettesFetcher)PaletteListDataSources.First(x => x is LocalPalettesFetcher);
+                return localPalettesFetcher ??= (LocalPalettesFetcher)PaletteListDataSources.First(x => x is LocalPalettesFetcher);
             }
             }
         }
         }
 
 
-        private LocalPalettesFetcher _localPalettesFetcher;
+        private LocalPalettesFetcher localPalettesFetcher;
 
 
-        private string[] _stopItTexts = new[]
+        private readonly string[] stopItTexts = new[]
         {
         {
             "That's enough. Tidy up your file names.",
             "That's enough. Tidy up your file names.",
             "Can you stop copying these names please?", "No, really, stop it.", "Don't you have anything better to do?"
             "Can you stop copying these names please?", "No, really, stop it.", "Don't you have anything better to do?"
@@ -169,12 +158,12 @@ namespace PixiEditor.Views.Dialogs
             Instance = this;
             Instance = this;
             DeletePaletteCommand = new RelayCommand<Palette>(DeletePalette);
             DeletePaletteCommand = new RelayCommand<Palette>(DeletePalette);
             ToggleFavouriteCommand = new RelayCommand<Palette>(ToggleFavourite, CanToggleFavourite);
             ToggleFavouriteCommand = new RelayCommand<Palette>(ToggleFavourite, CanToggleFavourite);
-            Loaded += async (sender, args) =>
+            Loaded += async (_, _) =>
             {
             {
                 LocalPalettesFetcher.CacheUpdated += LocalCacheRefreshed;
                 LocalPalettesFetcher.CacheUpdated += LocalCacheRefreshed;
                 await LocalPalettesFetcher.RefreshCacheAll();
                 await LocalPalettesFetcher.RefreshCacheAll();
             };
             };
-            Closed += (s, e) =>
+            Closed += (_, _) =>
             {
             {
                 Instance = null;
                 Instance = null;
                 LocalPalettesFetcher.CacheUpdated -= LocalCacheRefreshed;
                 LocalPalettesFetcher.CacheUpdated -= LocalCacheRefreshed;
@@ -248,7 +237,8 @@ namespace PixiEditor.Views.Dialogs
         private void HandleCacheItemUpdated(Palette updatedItem)
         private void HandleCacheItemUpdated(Palette updatedItem)
         {
         {
             var item = SortedResults.FirstOrDefault(x => x.FileName == updatedItem.FileName);
             var item = SortedResults.FirstOrDefault(x => x.FileName == updatedItem.FileName);
-            if (item == null) return;
+            if (item is null) 
+                return;
 
 
             item.Name = updatedItem.Name;
             item.Name = updatedItem.Name;
             item.IsFavourite = updatedItem.IsFavourite;
             item.IsFavourite = updatedItem.IsFavourite;
@@ -379,8 +369,8 @@ namespace PixiEditor.Views.Dialogs
         private async void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
         private async void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
         {
         {
             if (PaletteList?.Palettes == null) return;
             if (PaletteList?.Palettes == null) return;
-            var scrollViewer = (ScrollViewer)sender;
-            if (scrollViewer.VerticalOffset == scrollViewer.ScrollableHeight)
+            var viewer = (ScrollViewer)sender;
+            if (viewer.VerticalOffset == viewer.ScrollableHeight)
             {
             {
                 IsFetching = true;
                 IsFetching = true;
                 var newPalettes = await FetchPaletteList(0, Filtering);
                 var newPalettes = await FetchPaletteList(0, Filtering);
@@ -408,7 +398,7 @@ namespace PixiEditor.Views.Dialogs
 
 
         private async void ColorsComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
         private async void ColorsComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
         {
         {
-            if (e.AddedItems is { Count: > 0 } && e.AddedItems[0] is ComboBoxItem item && item.Content is string value)
+            if (e.AddedItems is { Count: > 0 } && e.AddedItems[0] is ComboBoxItem { Content: string value })
             {
             {
                 ColorsNumberMode = Enum.Parse<ColorsNumberMode>(value);
                 ColorsNumberMode = Enum.Parse<ColorsNumberMode>(value);
                 Filtering.ColorsNumberMode = ColorsNumberMode;
                 Filtering.ColorsNumberMode = ColorsNumberMode;
@@ -489,77 +479,33 @@ namespace PixiEditor.Views.Dialogs
 
 
         private async void AddFromPalette_OnClick(object sender, RoutedEventArgs e)
         private async void AddFromPalette_OnClick(object sender, RoutedEventArgs e)
         {
         {
-            if (CurrentEditingPalette?.Count == 0) return;
-
-            string finalFileName = "Unnamed Palette.pal";
-
-            string path = Path.Join(LocalPalettesFetcher.PathToPalettesFolder, finalFileName);
-            int i = 1;
-            while (File.Exists(path))
-            {
-                finalFileName = $"Unnamed Palette {i}.pal";
-                path = Path.Join(LocalPalettesFetcher.PathToPalettesFolder, finalFileName);
-                i++;
-            }
+            if (CurrentEditingPalette?.Count == 0) 
+                return;
 
 
+            string finalFileName = LocalPalettesFetcher.GetNonExistingName("Unnamed Palette.pal", true);
             await LocalPalettesFetcher.SavePalette(finalFileName, CurrentEditingPalette.ToArray());
             await LocalPalettesFetcher.SavePalette(finalFileName, CurrentEditingPalette.ToArray());
-
-            var palette = _localPalettesFetcher.CachedPalettes.FirstOrDefault(x => x.FileName == finalFileName);
-            if (palette != null)
-            {
-                if (SortedResults == null)
-                {
-                    SortedResults = new WpfObservableRangeCollection<Palette>();
-                }
-
-                if (SortedResults.Contains(palette))
-                {
-                    SortedResults.Move(SortedResults.IndexOf(palette), 0);
-                }
-                else
-                {
-                    SortedResults.Insert(0, palette);
-                }
-            }
         }
         }
 
 
         private void PaletteItem_OnRename(object sender, EditableTextBlock.TextChangedEventArgs e)
         private void PaletteItem_OnRename(object sender, EditableTextBlock.TextChangedEventArgs e)
         {
         {
             PaletteItem item = (PaletteItem)sender;
             PaletteItem item = (PaletteItem)sender;
-            string oldFileName = $"{e.OldText}.pal";
-
+            item.Palette.Name = e.OldText;
+            
             if (string.IsNullOrWhiteSpace(e.NewText) || e.NewText == item.Palette.Name || e.NewText.Length > 50)
             if (string.IsNullOrWhiteSpace(e.NewText) || e.NewText == item.Palette.Name || e.NewText.Length > 50)
-            {
-                item.Palette.FileName = oldFileName;
-                item.Palette.Name = e.OldText;
                 return;
                 return;
-            }
 
 
-            string oldPath = Path.Join(LocalPalettesFetcher.PathToPalettesFolder, oldFileName);
-
-            string finalNewName = $"{Palette.ReplaceInvalidChars(e.NewText)}.pal";
-            string newPath = Path.Join(LocalPalettesFetcher.PathToPalettesFolder, LocalPalettesFetcher.GetNonExistingName(finalNewName, true));
+            string oldFileName = $"{e.OldText}.pal";
+            
+            string finalNewName = LocalPalettesFetcher.GetNonExistingName($"{Palette.ReplaceInvalidChars(e.NewText)}.pal", true);
+            string newPath = Path.Join(LocalPalettesFetcher.PathToPalettesFolder, finalNewName);
 
 
             if (newPath.Length > 250)
             if (newPath.Length > 250)
             {
             {
-                NoticeDialog.Show(_stopItTexts[Random.Shared.Next(_stopItTexts.Length - 1)], "The name is too long.");
+                NoticeDialog.Show(stopItTexts[Random.Shared.Next(stopItTexts.Length - 1)], "The name is too long.");
                 return;
                 return;
             }
             }
-
-            if (!File.Exists(oldPath))
-            {
-                item.Palette.FileName = oldFileName;
-                item.Palette.Name = e.OldText;
-                return;
-            }
-
-
-            File.Move(oldPath, newPath);
-
-            item.Palette.FileName = finalNewName;
-            item.Palette.Name = e.NewText;
-
-            HandleCacheItemRenamed(item.Palette, oldFileName);
+            
+            LocalPalettesFetcher.RenamePalette(oldFileName, finalNewName);
         }
         }
 
 
         private static void UpdateRenamedFavourite(string old, string newName)
         private static void UpdateRenamedFavourite(string old, string newName)